-
Notifications
You must be signed in to change notification settings - Fork 0
all

The Token class represents a token that has been parsed from a JSON string. It includes the start and end indices of the token within the source, as well as its type. The class provides methods for getting the string representation of the token, as well as its length and a string representation that includes its start and end indices and type. Additionally, the class includes equals and hashCode methods for comparing tokens.

JsonParserBuilder
Builder class for creating instances of JsonParser.
Please refer to JsonParserBuilder#build() for details on how the build logic is formed.
public JsonParser build() {
if (strict()) {
return new JsonStrictParser(objectsKeysCanBeEncoded());
} else if (isSupportNoQuoteKeys() || isAllowHashComment() || isAllowSlashSlashComment() || isAllowSlashStarComment() || parseKey != null) {
final ParseFunction[] funcTable = this.getFuncTable();
funcTable[ParseConstants.STRING_START_TOKEN] = JsonParserFunctions::parseString;
funcTable[ParseConstants.NULL_START] = JsonParserFunctions::parseNull;
funcTable[ParseConstants.TRUE_BOOLEAN_START] = JsonParserFunctions::parseTrue;
funcTable[ParseConstants.FALSE_BOOLEAN_START] = JsonParserFunctions::parseFalse;
for (int i = ParseConstants.NUM_0; i < ParseConstants.NUM_9 + 1; i++) {
funcTable[i] = JsonParserFunctions::parseNumber;
}
funcTable[ParseConstants.MINUS] = JsonParserFunctions::parseNumber;
funcTable[ParseConstants.PLUS] = JsonParserFunctions::parseNumber;
if (isAllowHashComment()) {
funcTable['#'] = (source, tokens) -> source.findChar('\n');
}
if (isSupportNoQuoteKeys() && getParseKey() == null) {
setParseKey(JsonParserFunctions::parseKeyNoQuote);
}
if (isAllowSlashStarComment() || isAllowSlashSlashComment()) {
funcTable['/'] = (source, tokens) -> {
int next = source.next();
if (next == '/') {
source.findChar('\n');
} else if (next == '*') {
loop: while (source.findChar('*')) {
switch(source.next()) {
case '/':
break loop;
case ParseConstants.ETX:
throw new UnexpectedCharacterException("Comment parse", "End of stream", source);
}
}
}
};
}
return new JsonFuncParser(objectsKeysCanBeEncoded(), Arrays.copyOf(funcTable, funcTable.length), this.getDefaultFunc(), this.getParseKey());
} else {
return new JsonFastParser(objectsKeysCanBeEncoded());
}
}The build() method in the JsonParserBuilder class is responsible for creating and returning an instance of JsonParser based on the configuration set in the builder. Here is a step-by-step description of what the method is doing:
- If the
strict()flag is set to true, a newJsonStrictParserinstance is created with theobjectsKeysCanBeEncoded()flag and returned. - If the
isSupportNoQuoteKeys(),isAllowHashComment(),isAllowSlashSlashComment(), orisAllowSlashStarComment()flags are set to true, or if theparseKeyis not null, additional configuration is applied to theJsonParser. - An array of
ParseFunctioncalledfuncTableis retrieved using thegetFuncTable()method. - The
funcTableis populated with different parse functions for each token or character:- The
STRING_START_TOKENis mapped toJsonParserFunctions::parseString. - The
NULL_STARTis mapped toJsonParserFunctions::parseNull. - The
TRUE_BOOLEAN_STARTis mapped toJsonParserFunctions::parseTrue. - The
FALSE_BOOLEAN_STARTis mapped toJsonParserFunctions::parseFalse. - The numbers from
NUM_0toNUM_9are mapped toJsonParserFunctions::parseNumber. - The
MINUSis mapped toJsonParserFunctions::parseNumber. - The
PLUSis mapped toJsonParserFunctions::parseNumber. - If the
isAllowHashComment()flag is true, the#character is mapped to a lambda function that finds the next character on a new line. - If the
isSupportNoQuoteKeys()flag is true and theparseKeyis null, theparseKeyNoQuotefunction is set as theparseKeyin the builder. - If the
isAllowSlashStarComment()orisAllowSlashSlashComment()flags are true, the/character is mapped to a lambda function that handles comments. If the next character is/, it finds the next character on a new line. If the next character is*, it processes the comment until it finds*/.
- The
- Finally, if none of the above conditions are met, a new
JsonFastParserinstance is created with theobjectsKeysCanBeEncoded()flag and returned.
The returned JsonParser instance has different behavior based on the configuration options set in the builder.

public JsonEventParser buildEventParser() {
if (strict()) {
return new JsonEventStrictParser(objectsKeysCanBeEncoded(), tokenEventListener());
} else {
return new JsonEventFastParser(objectsKeysCanBeEncoded(), tokenEventListener());
}
}The buildEventParser method in the JsonParserBuilder class is designed to create and return an instance of the JsonEventParser interface. Here is a step-by-step description of what the method does based on its body:
-
Check if the
strict()method returns true.- If true, proceed to step 2.
- If false, proceed to step 3.
-
Create a new instance of the
JsonEventStrictParserclass.- Pass the result of the
objectsKeysCanBeEncoded()method as the first argument. - Pass the result of the
tokenEventListener()method as the second argument. - Return the created
JsonEventStrictParserinstance.
- Pass the result of the
-
Create a new instance of the
JsonEventFastParserclass.- Pass the result of the
objectsKeysCanBeEncoded()method as the first argument. - Pass the result of the
tokenEventListener()method as the second argument. - Return the created
JsonEventFastParserinstance.
- Pass the result of the
Note that the choice between using JsonEventStrictParser and JsonEventFastParser depends on the return value of the strict() method. If strict() is true, the strict parser is used; otherwise, the fast parser is used.


The JsonParserFunctions class is a collection of functions that are utilized by the JsonFuncParser to parse JSON.
public static boolean parseKeyNoQuote(final CharSource source, final TokenList tokens) {
int ch = source.nextSkipWhiteSpace();
final int startIndex = source.getIndex() - 1;
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean found = false;
switch(ch) {
case ParseConstants.STRING_START_TOKEN:
final int strStartIndex = startIndex + 1;
final int strEndIndex = source.findEndOfEncodedString();
tokens.add(new Token(strStartIndex + 1, strEndIndex, TokenTypes.STRING_TOKEN));
found = true;
break;
case ParseConstants.OBJECT_END_TOKEN:
tokens.undoPlaceholder();
return true;
default:
if (Character.isAlphabetic(ch)) {
final int start = source.getIndex();
final int end = source.findAttributeEnd();
tokens.add(new Token(start, end, TokenTypes.STRING_TOKEN));
found = true;
} else {
throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
}
}
boolean done = source.findObjectEndOrAttributeSep();
if (!done && found) {
tokens.set(tokenListIndex, new Token(startIndex + 1, source.getIndex(), TokenTypes.ATTRIBUTE_KEY_TOKEN));
} else if (found && done) {
throw new UnexpectedCharacterException("Parsing key", "Not found", source);
}
return done;
}The method parseKeyNoQuote in the JsonParserFunctions class takes two parameters: source of type CharSource and tokens of type TokenList. It returns a boolean value.
Here is a step-by-step description of what the method does based on its body:
- It retrieves the next character from the
sourceand skips any leading white spaces. - It saves the current index of the
sourceminus 1 asstartIndex. - It saves the current index of the
tokensastokenListIndex. - It adds a placeholder token to the
tokenslist. - It initializes a boolean variable
foundas false. - It enters a switch statement based on the value of the character
ch.- If
chis equal toParseConstants.STRING_START_TOKEN:- It calculates the start index of the string as
strStartIndexby adding 1 tostartIndex. - It calculates the end index of the string as
strEndIndexby calling thefindEndOfEncodedStringmethod on thesourceobject. - It adds a new
Tokenobject to thetokenslist with the start index, end index, and typeTokenTypes.STRING_TOKEN. - It sets
foundto true.
- It calculates the start index of the string as
- If
chis equal toParseConstants.OBJECT_END_TOKEN:- It undoes the placeholder token added to the
tokenslist. - It returns true.
- It undoes the placeholder token added to the
- If
chis neitherParseConstants.STRING_START_TOKENnorParseConstants.OBJECT_END_TOKEN:- If
chis an alphabetic character:- It saves the current index of the
sourceasstart. - It finds the end index of the attribute by calling the
findAttributeEndmethod on thesourceobject and saves it asend. - It adds a new
Tokenobject to thetokenslist with the start index, end index, and typeTokenTypes.STRING_TOKEN. - It sets
foundto true.
- It saves the current index of the
- If
chis not an alphabetic character:- It throws an
UnexpectedCharacterExceptionwith the message "Unexpected character found" and thesourceobject as arguments.
- It throws an
- If
- If
- It checks if it needs to find the end of the object or the attribute separator by calling the
findObjectEndOrAttributeSepmethod on thesourceobject. The result is saved in thedonevariable. - If
doneis false andfoundis true:- It updates the placeholder token in the
tokenslist with the start index asstartIndex + 1and the current index of thesourceas the end index, and the typeTokenTypes.ATTRIBUTE_KEY_TOKEN.
- It updates the placeholder token in the
- If
foundis true anddoneis true:- It throws an
UnexpectedCharacterExceptionwith the message "Not found" and thesourceobject as arguments.
- It throws an
- It returns the value of
done.
public static boolean parseKeyWithEncode(final CharSource source, final TokenList tokens) {
int ch = source.nextSkipWhiteSpace();
final int startIndex = source.getIndex() - 1;
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean found = false;
switch(ch) {
case ParseConstants.STRING_START_TOKEN:
final int strStartIndex = startIndex + 1;
final int strEndIndex = source.findEndOfEncodedString();
tokens.add(new Token(strStartIndex + 1, strEndIndex, TokenTypes.STRING_TOKEN));
found = true;
break;
case ParseConstants.OBJECT_END_TOKEN:
tokens.undoPlaceholder();
return true;
default:
throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
}
boolean done = source.findObjectEndOrAttributeSep();
if (!done && found) {
tokens.set(tokenListIndex, new Token(startIndex + 1, source.getIndex(), TokenTypes.ATTRIBUTE_KEY_TOKEN));
} else if (found && done) {
throw new UnexpectedCharacterException("Parsing key", "Not found", source);
}
return done;
}The parseKeyWithEncode method is defined in the io.nats.jparse.parser.functable.JsonParserFunctions class. It takes two parameters: source of type CharSource and tokens of type TokenList. The method has a return type of boolean.
The purpose of this method is to parse a key while encoding it, given a character source (source) and a list of tokens (tokens).
Below is a step-by-step description of what the method does:
-
The method starts by retrieving the next character from the
source, skipping any white space characters. -
It initializes two variables:
startIndexto hold the index of the character in thesourceminus 1 andtokenListIndexto hold the current index of thetokenslist. -
A placeholder token is added to the
tokenslist. -
The method enters a
switchstatement based on the value of the retrieved character. -
If the retrieved character is equal to the constant
ParseConstants.STRING_START_TOKEN, the method proceeds to parse a string. It initializes two variables:strStartIndexto hold the index of the start of the string plus 1 andstrEndIndexto hold the index of the end of the encoded string. A newTokenobject is created with the start and end indexes, and a token type ofTokenTypes.STRING_TOKEN. The newly created token is added to thetokenslist. Thefoundvariable is set totrue. -
If the retrieved character is equal to the constant
ParseConstants.OBJECT_END_TOKEN, the method undoes the placeholder token and returnstrue. -
If none of the above cases match, an
UnexpectedCharacterExceptionis thrown, indicating that an unexpected character was found while parsing the key. -
The method then tries to find the end of the object or the attribute separator. The
donevariable is set totrueif the end is found. -
If
doneisfalseandfoundistrue, the method updates the token at thetokenListIndexin thetokenslist with a newTokenobject that has the updated start and end indexes, and a token type ofTokenTypes.ATTRIBUTE_KEY_TOKEN. -
If
foundistrueanddoneistrue, anUnexpectedCharacterExceptionis thrown, indicating that the key was not found. -
Finally, the method returns the value of the
donevariable.
This method is used to parse a key while encoding it, and it handles different cases based on the character read from the source. If the key is successfully parsed, the method updates the tokens list accordingly. However, if an unexpected character is encountered or the key is not found, an exception is thrown.

public static boolean parseKeyNoEncode(final CharSource source, final TokenList tokens) {
int ch = source.nextSkipWhiteSpace();
final int startIndex = source.getIndex() - 1;
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean found = false;
switch(ch) {
case ParseConstants.STRING_START_TOKEN:
final int strStartIndex = startIndex + 1;
final int strEndIndex = source.findEndString();
tokens.add(new Token(strStartIndex + 1, strEndIndex, TokenTypes.STRING_TOKEN));
found = true;
break;
case ParseConstants.OBJECT_END_TOKEN:
tokens.undoPlaceholder();
return true;
default:
throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
}
boolean done = source.findObjectEndOrAttributeSep();
if (!done && found) {
tokens.set(tokenListIndex, new Token(startIndex + 1, source.getIndex(), TokenTypes.ATTRIBUTE_KEY_TOKEN));
} else if (found && done) {
throw new UnexpectedCharacterException("Parsing key", "Not found", source);
}
return done;
}
The JsonFuncParser class is an implementation of the JsonParser interface. It uses a function table to define the behavior of the parser. The function table, which is an array of ParseFunction objects, determines which function to call when parsing a specific character. The function table can be customized by subclassing this class and overriding the initFuncTable method. Additionally, the function table can be configured using the JsonParserBuilder.
private void doParse(final CharSource source, final TokenList tokens, final int ch) {
if (ch < 256) {
funcTable[ch].parse(source, tokens);
} else {
defaultFunc.parse(source, tokens);
}
}The method doParse defined in class io.nats.jparse.parser.functable.JsonFuncParser is a private method with the following step-by-step description:
- Accepts three parameters:
sourceof typeCharSource,tokensof typeTokenList, andchof typeint. - Checks if the value of
chis less than 256. - If
chis less than 256: a. Retrieves the appropriate parser from thefuncTablearray at indexch. b. Invokes theparsemethod on the retrieved parser, passingsourceandtokensas arguments. - If
chis not less than 256: a. Invokes theparsemethod on thedefaultFunc, passingsourceandtokensas arguments.
This method essentially determines the appropriate parser to use based on the value of ch and delegates the parsing task to the selected parser using the parse method.

private void parseArray(final CharSource source, final TokenList tokens) {
final int startSourceIndex = source.getIndex();
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean done = false;
while (!done) {
done = parseArrayItem(source, tokens);
}
final Token arrayToken = new Token(startSourceIndex, source.getIndex(), TokenTypes.ARRAY_TOKEN);
tokens.set(tokenListIndex, arrayToken);
}The method parseArray is defined in the class io.nats.jparse.parser.functable.JsonFuncParser. It takes two parameters: source of type CharSource and tokens of type TokenList.
Here is a step-by-step description of what the method does:
- It stores the current index of the source in a variable called
startSourceIndex. - It also stores the current index of the
tokensin a variable calledtokenListIndex. - It inserts a placeholder token in the
tokenslist using theplaceHolder()method. - It initializes a boolean variable called
doneto false. - It enters a while loop that continues until
donebecomes true. - Inside the while loop, it calls the
parseArrayItem()method passingsourceandtokensas parameters. TheparseArrayItem()method is responsible for parsing each item in the array. - After
parseArrayItem()returns, it checks the value ofdoneand updates it accordingly. - Once all the items in the array have been parsed, it creates a new
Tokenobject calledarrayTokenusing thestartSourceIndex, current index of thesource, and the typeTokenTypes.ARRAY_TOKEN. - Finally, it updates the token at
tokenListIndexin thetokenslist with the newly createdarrayToken.
That's the step-by-step description of what the parseArray method does based on its body.

private boolean parseArrayItem(CharSource source, TokenList tokens) {
char ch = (char) source.nextSkipWhiteSpace();
forLoop: for (; ch != ETX; ch = (char) source.nextSkipWhiteSpace()) {
switch(ch) {
case ARRAY_END_TOKEN:
source.next();
return true;
case ARRAY_SEP:
source.next();
return false;
default:
doParse(source, tokens, ch);
break forLoop;
}
}
if (source.getCurrentChar() == ARRAY_END_TOKEN) {
source.next();
return true;
}
return false;
}The parseArrayItem method is defined in the JsonFuncParser class, which is located in the package io.nats.jparse.parser.functable.
This method takes two parameters:
-
sourceof typeCharSource, which represents the source of characters to parse. -
tokensof typeTokenList, which represents the list of tokens that have been parsed so far.
Here is a step-by-step description of what the parseArrayItem method does based on its body:
- Retrieve the next character from the
sourceand assign it to the variablech. Skip any whitespace characters. - Start a
forloop that iterates until the characterETX(end of text) is encountered. - Within the
forloop, check the value ofchusing aswitchstatement. - If
chis equal toARRAY_END_TOKEN(representing the end of the array), move the source to the next character and returntrueto indicate that the array item has been successfully parsed. - If
chis equal toARRAY_SEP(representing the separator between array items), move the source to the next character and returnfalseto indicate that more array items need to be parsed. - If none of the above cases match (i.e.,
chis any other character), call thedoParsemethod to further parse the item using the current characterch. Then, break out of theforloop to stop parsing the current array item and move on to the next one. - After the
forloop ends, check if the current character in thesourceis equal toARRAY_END_TOKEN. - If it is, move the source to the next character and return
trueto indicate that the array item has been successfully parsed. - If the current character in the
sourceis not equal toARRAY_END_TOKEN, returnfalseto indicate that the array item has not been fully parsed yet.
That's the step-by-step description of what the parseArrayItem method does based on its body.

private boolean parseValue(final CharSource source, TokenList tokens) {
int ch = source.nextSkipWhiteSpace();
final int startIndex = source.getIndex();
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
doParse(source, tokens, ch);
ch = source.skipWhiteSpace();
switch(ch) {
case OBJECT_END_TOKEN:
if (source.getIndex() == tokenListIndex) {
throw new UnexpectedCharacterException("Parsing Value", "Key separator before value", source);
}
tokens.set(tokenListIndex, new Token(startIndex, source.getIndex(), TokenTypes.ATTRIBUTE_VALUE_TOKEN));
return true;
case OBJECT_ATTRIBUTE_SEP:
if (source.getIndex() == tokenListIndex) {
throw new UnexpectedCharacterException("Parsing Value", "Key separator before value", source);
}
tokens.set(tokenListIndex, new Token(startIndex, source.getIndex(), TokenTypes.ATTRIBUTE_VALUE_TOKEN));
return false;
default:
throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, source.getCurrentChar());
}
}The parseValue method in the JsonFuncParser class is used to parse a JSON value from a given source and add it to a list of tokens. Here is a step-by-step description of the method's functionality:
- Get the next character from the source, skipping any white spaces.
- Store the current index of the source as the starting index of the value.
- Store the current index of the tokens list.
- Create a placeholder token in the tokens list to represent the parsed value. This placeholder will be replaced later with the actual value token.
- Call the
doParsemethod to parse the value and update the tokens list. - Get the next character from the source after parsing the value, skipping any white spaces.
- Check the value of the next character using a switch statement.
- If the next character is an object end token, check that the source index is equal to the token list index. If it is not, throw an
UnexpectedCharacterExceptionindicating that there was a key separator before the value. Otherwise, update the placeholder token in the token list with the correct start and end indexes and set its type asATTRIBUTE_VALUE_TOKEN. Finally, returntrueto indicate that the parsing is successful. - If the next character is an object attribute separator, perform the same check as in step 8. If the check fails, throw an
UnexpectedCharacterExceptionindicating that there was a key separator before the value. Otherwise, update the placeholder token in the token list with the correct start and end indexes and set its type asATTRIBUTE_VALUE_TOKEN. Finally, returnfalseto indicate that the parsing is not yet complete. - If none of the above cases match, throw an
UnexpectedCharacterExceptionindicating that there is an unexpected character in the value, along with the current character from the source.
This method is responsible for parsing a JSON value from a source and adding it to the tokens list, while also handling different scenarios such as object end token and object attribute separator.

private void parseObject(final CharSource source, TokenList tokens) {
final int startSourceIndex = source.getIndex();
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean done = false;
while (!done) {
done = parseKey.parse(source, tokens);
if (!done)
done = parseValue(source, tokens);
}
source.next();
tokens.set(tokenListIndex, new Token(startSourceIndex, source.getIndex(), TokenTypes.OBJECT_TOKEN));
}The parseObject() method in the class io.nats.jparse.parser.functable.JsonFuncParser is responsible for parsing a JSON object. Here is a step-by-step description of what this method is doing based on its body:
-
The method begins by creating two local variables:
startSourceIndexandtokenListIndex. These variables are assigned the current index of the source and tokens. -
The
tokens.placeHolder()method is called to create a placeholder token in thetokenslist. -
A boolean variable named
doneis declared and initialized asfalse. This variable is used to indicate whether the parsing of the object is complete. -
A while loop is started with the condition
!done. This loop continues until the parsing of the object is complete. -
The
parseKey.parse(source, tokens)method is called to parse a key from the source. If the parsing is successful and returnstrue, the value ofdoneis set totrue, indicating that the parsing of the object is complete. If the parsing of the key is not successful, the methodparseValue(source, tokens)is called to parse a value. -
Once the parsing of the object is complete, the
source.next()method is called to move the index of the source to the next character. -
The
tokens.set(tokenListIndex, new Token(startSourceIndex, source.getIndex(), TokenTypes.OBJECT_TOKEN))method is called to set the token attokenListIndexto a newTokenobject representing the parsed JSON object. ThestartSourceIndexis the starting index of the object, and the current index of the source is the ending index of the object. TheTokenTypes.OBJECT_TOKENindicates that the token represents an object.
In summary, the parseObject() method parses a JSON object by repeatedly calling methods to parse keys and values until the entire object is parsed. It then updates the tokens list with a new token representing the parsed object.


The JsonEventFastParser class is a public class that extends the JsonEventAbstractParser. It is a fast JSON event parser.
public void parseWithEvents(CharSource source, final TokenEventListener event)
@Override
public void parseWithEvents(CharSource source, final TokenEventListener event) {
int ch = source.nextSkipWhiteSpace();
switch(ch) {
case OBJECT_START_TOKEN:
parseObject(source, event);
break;
case ARRAY_START_TOKEN:
parseArray(source, event);
break;
case TRUE_BOOLEAN_START:
parseTrue(source, event);
break;
case FALSE_BOOLEAN_START:
parseFalse(source, event);
break;
case NULL_START:
parseNull(source, event);
break;
case STRING_START_TOKEN:
parseString(source, event);
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
parseNumber(source, event);
break;
default:
throw new UnexpectedCharacterException("Scanning JSON", "Unexpected character", source, (char) ch);
}
}The parseWithEvents method in the JsonEventFastParser class is used to parse JSON content with event callbacks. Here is a step-by-step description of what this method does:
-
It takes two parameters:
source, which is aCharSourceobject representing the JSON content to parse, andevent, which is aTokenEventListenerobject that will receive the parsing events. -
The method calls
source.nextSkipWhiteSpace()to read the next character from thesourceand skips any leading white spaces. The returned value is stored in thechvariable. -
It enters a
switchstatement based on the value ofch. -
If
chequalsOBJECT_START_TOKEN, the method calls theparseObjectmethod, passing thesourceandeventparameters. This method is responsible for parsing JSON objects. -
If
chequalsARRAY_START_TOKEN, the method calls theparseArraymethod, passing thesourceandeventparameters. This method is responsible for parsing JSON arrays. -
If
chequalsTRUE_BOOLEAN_START, the method calls theparseTruemethod, passing thesourceandeventparameters. This method is responsible for parsing the JSON "true" boolean value. -
If
chequalsFALSE_BOOLEAN_START, the method calls theparseFalsemethod, passing thesourceandeventparameters. This method is responsible for parsing the JSON "false" boolean value. -
If
chequalsNULL_START, the method calls theparseNullmethod, passing thesourceandeventparameters. This method is responsible for parsing the JSON "null" value. -
If
chequalsSTRING_START_TOKEN, the method calls theparseStringmethod, passing thesourceandeventparameters. This method is responsible for parsing JSON strings. -
If
chequals any of the number-related characters (NUM_0,NUM_1,NUM_2, etc.), the method calls theparseNumbermethod, passing thesourceandeventparameters. This method is responsible for parsing JSON numeric values. -
If none of the above cases match, it means that an unexpected character was encountered, and the method throws an
UnexpectedCharacterException, passing a message, the current source, and the unexpected character.
Overall, the parseWithEvents method determines the type of JSON value based on the first character of the input source, and then delegates the parsing to specific methods accordingly. It ensures that the appropriate parsing method is called based on the type of JSON token encountered, and if an unexpected character is encountered, it throws an exception.
The method parseWithEvents in the JsonEventFastParser class is used to parse a JSON input using an event-based approach. It takes a CharSource object representing the input source and a TokenEventListener object to handle the parsing events.
Within the method, it reads the first character from the input source and determines the type of token it represents. Based on the token, the method dispatches the parsing task to corresponding methods such as parseObject, parseArray, parseTrue, parseFalse, parseNull, parseString, or parseNumber.
If the first character does not match any of the expected JSON tokens, it throws an exception indicating an unexpected character.
Overall, this method enables parsing of JSON input using event-based parsing technique, where the parser notifies the listener about different events encountered during parsing, such as the start and end of JSON objects or arrays, the discovery of boolean values, null values, strings, or numeric values.

private void parseArray(final CharSource source, final TokenEventListener event) {
event.start(TokenTypes.ARRAY_TOKEN, source.getIndex(), source);
boolean done = false;
while (!done) {
done = parseArrayItem(source, event);
if (!done) {
done = source.findCommaOrEndForArray();
}
}
event.end(TokenTypes.ARRAY_TOKEN, source.getIndex(), source);
}The parseArray method in the JsonEventFastParser class is responsible for parsing JSON arrays. Here is a step-by-step breakdown of what this method does:
-
The method takes two arguments:
source, which is aCharSourceobject representing the source of the JSON data, andevent, which is aTokenEventListenerobject used for notifying events during parsing. -
The method starts by calling the
startmethod of theeventobject to notify the start of an array token, providing the token type, the index of the source, and the source itself. -
A boolean variable
doneis initialized tofalse, indicating the parsing process is not yet completed. -
The method enters a while loop that continues until the parsing is complete (indicated by
donebeing set totrue). -
Inside the loop, the method calls the
parseArrayItemmethod to parse each item in the array. This method is responsible for handling the inner elements of the array and returns a boolean value indicating whether the parsing for the item is complete or not. -
If the parsing for the current item is not complete (indicated by the returned value of
parseArrayItembeingfalse), the method calls thefindCommaOrEndForArraymethod of thesourceobject. This method is responsible for finding the next comma separator or the end of the array in the source and returns a boolean value indicating whether the parsing for the array is complete or not. -
The while loop continues or terminates based on the value of
done. Ifdoneistrue, the parsing is complete, and the loop will exit. -
Finally, the method calls the
endmethod of theeventobject to notify the end of the array token, providing the token type, the index of the source, and the source itself.
This method essentially iterates over the elements of a JSON array, calling the appropriate parsing methods and notifying the events to the TokenEventListener during the process.
The parseArray method in the JsonEventFastParser class is used to parse an array from a given input source and notify the provided TokenEventListener of the encountered array tokens.
The method starts by calling the start method of the TokenEventListener to notify the start of the array token.
Then, it enters a loop to parse each item in the array. It calls the parseArrayItem method to parse each item, and if the parsing is not yet done, it checks if there is a comma (,) or end (]) of the array.
Once the parsing is done, it calls the end method of the TokenEventListener to notify the end of the array token.

private boolean parseArrayItem(CharSource source, final TokenEventListener event) {
char startChar = source.getCurrentChar();
int ch = source.nextSkipWhiteSpace();
switch(ch) {
case OBJECT_START_TOKEN:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseObject(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case ARRAY_START_TOKEN:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseArray(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case TRUE_BOOLEAN_START:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseTrue(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case FALSE_BOOLEAN_START:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseFalse(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case NULL_START:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseNull(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case STRING_START_TOKEN:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseString(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseNumber(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
if (source.getCurrentChar() == ARRAY_END_TOKEN || source.getCurrentChar() == ARRAY_SEP) {
if (source.getCurrentChar() == ARRAY_END_TOKEN) {
source.next();
return true;
}
}
break;
case ARRAY_END_TOKEN:
if (startChar == ARRAY_SEP) {
throw new UnexpectedCharacterException("Parsing Array Item", "Trailing comma", source, (char) ch);
}
source.next();
return true;
default:
throw new UnexpectedCharacterException("Parsing Array Item", "Unexpected character", source, (char) ch);
}
return false;
}The parseArrayItem method is responsible for parsing an item within a JSON array. Here is a step-by-step description of what this method does based on its body:
-
The method takes two parameters: a
CharSourceobject, which represents the source of characters to be parsed, and aTokenEventListenerobject, which handles the parsing events. -
The method starts by getting the current character from the
CharSourceand storing it in thestartCharvariable. It then calls thenextSkipWhiteSpacemethod on theCharSourceto get the next non-whitespace character and stores it in thechvariable. -
The method performs a switch statement on the value of
chto determine the type of JSON value to be parsed:-
If
chis equal toOBJECT_START_TOKEN, it means that the item is an object. The method calls thestartmethod on theTokenEventListenerto indicate the start of an array item, followed by invoking theparseObjectmethod to parse the nested object. After parsing the object, theendmethod is called on theTokenEventListenerto indicate the end of the array item. -
If
chis equal toARRAY_START_TOKEN, it means that the item is an array. The method follows the same steps as described for the object case, but calls theparseArraymethod instead to parse the nested array. -
If
chis equal toTRUE_BOOLEAN_START, it means that the item is a boolean valuetrue. The method follows the same steps as described for the object case, but calls theparseTruemethod instead to parse the valuetrue. -
If
chis equal toFALSE_BOOLEAN_START, it means that the item is a boolean valuefalse. The method follows the same steps as described for the object case, but calls theparseFalsemethod instead to parse the valuefalse. -
If
chis equal toNULL_START, it means that the item is a null value. The method follows the same steps as described for the object case, but calls theparseNullmethod instead to parse the valuenull. -
If
chis equal toSTRING_START_TOKEN, it means that the item is a string value. The method follows the same steps as described for the object case, but calls theparseStringmethod instead to parse the string value. -
If
chis one of the charactersNUM_0toNUM_9,MINUS, orPLUS, it means that the item is a numeric value. The method follows the same steps as described for the object case, but calls theparseNumbermethod instead to parse the numeric value. After parsing the number, it checks if the current character in the source is either theARRAY_END_TOKENor theARRAY_SEP. If it's theARRAY_END_TOKEN, it means that the array ends after this item, so the method returnstrueto indicate that the parsing of the array is complete. If it's theARRAY_SEP, it means that more items are present in the array, so the method continues parsing the next item by returningfalse. -
If
chis equal toARRAY_END_TOKEN, it means that the array ends after this item. The method checks if thestartCharis theARRAY_SEPcharacter, which indicates a trailing comma in the array. If it's a trailing comma, the method throws anUnexpectedCharacterExceptionwith a message indicating the presence of a trailing comma. Otherwise, it simply moves to the next character in the source and returnstrueto indicate that the parsing of the array is complete. -
If none of the above cases match, it means that the character
chis not a valid character for an item in the JSON array. The method throws anUnexpectedCharacterExceptionwith a message indicating that an unexpected character was encountered while parsing the array item.
-
-
Finally, if none of the above cases match and no exception is thrown, the method returns
falseto indicate that the parsing of the array is not yet complete and there are more items to be parsed.
This is a general overview of the parseArrayItem method and its behavior based on the provided code snippet.
The parseArrayItem method in the JsonEventFastParser class is responsible for parsing an item within a JSON array.
It takes in a CharSource object, which represents the source of characters to be parsed, and a TokenEventListener object, which handles the events generated during parsing.
The method starts by getting the current character from the CharSource and then reads the next character after skipping any white space.
It then checks the value of the character and performs different actions based on its value. If the character indicates the start of an object, it calls the parseObject method and generates the appropriate start and end tokens for the array item. Similarly, if the character indicates the start of an array, boolean value (true/false), null value, string, or number, it calls the respective parsing methods and generates the corresponding tokens.
If the character is a digit or special character that indicates the start of a number, the method parses the number and checks if the current character is either the end of the array or a comma separator. If it is the end of the array, the method returns true to indicate that the item has been parsed successfully.
If the character is the end token of an array, the method returns true if and only if the start character of the array item is a comma separator. This is to check if there is a trailing comma after the last item in the array, which is not allowed in JSON.
If none of the above conditions are met, the method throws an exception indicating that an unexpected character was encountered.
Finally, the method returns false to indicate that the item has not been fully parsed yet.
This method is used internally by the parser to parse individual items within a JSON array.
private void parseNumber(final CharSource source, final TokenEventListener event) {
final int startIndex = source.getIndex();
final NumberParseResult numberParse = source.findEndOfNumber();
final int tokenType = numberParse.wasFloat() ? TokenTypes.FLOAT_TOKEN : TokenTypes.INT_TOKEN;
event.start(tokenType, startIndex, source);
event.end(tokenType, numberParse.endIndex(), source);
}The parseNumber method, which is defined in the class io.nats.jparse.parser.event.JsonEventFastParser, is responsible for parsing numbers from a given character source and notifying a token event listener about the parsed number.
Here is a step-by-step description of what the parseNumber method does:
-
It takes two parameters:
source, which is the character source containing the JSON string, andevent, which is the token event listener that will be notified about the parsed number. -
It retrieves the current index of the character source using the
getIndex()method and assigns it to thestartIndexvariable. This will be the starting index of the parsed number. -
It calls the
findEndOfNumber()method on thesourceobject to find the end index of the number. This method scans the character source and determines the end index of the number, taking into account the decimal point and scientific notation if present. The result of this operation is stored in thenumberParsevariable, which is of typeNumberParseResult. -
It determines the token type based on the result of the
wasFloat()method called onnumberParse. If the parsed number is a float, the token type is set toTokenTypes.FLOAT_TOKEN. Otherwise, it is set toTokenTypes.INT_TOKEN. -
It notifies the token event listener that a number token is starting by calling the
start()method onevent. This method takes three parameters: the token type, thestartIndex, and thesourceobject. This allows the event listener to handle the start of a number token. -
It notifies the token event listener that a number token has ended by calling the
end()method onevent. This method also takes three parameters: the token type, the end index obtained fromnumberParse, and thesourceobject. This allows the event listener to handle the end of a number token.
Overall, the parseNumber method scans the character source to find the end index of a number, determines its type (float or integer), and notifies the token event listener about the start and end of the number token.
The parseNumber method in the JsonEventFastParser class is responsible for parsing a number from a given CharSource and notifying the TokenEventListener about the parsed number.
Here is a breakdown of what the method does:
- It saves the starting index of the current parsing position in the
sourceusingsource.getIndex(). - Then, it uses the
findEndOfNumber()method of thesourceto parse the number and stores the result innumberParse. - Next, it determines the
tokenTypebased on whether the parsed number was a float or an integer, using thewasFloat()method ofnumberParse. - It notifies the
TokenEventListenerthat a new token is starting by calling itsstart()method with thetokenType, thestartIndex, and thesource. - Finally, it notifies the
TokenEventListenerthat the token has ended by calling itsend()method with thetokenType, theendIndex()obtained fromnumberParse, and thesource.
In summary, the parseNumber method parses a number from the source and lets the TokenEventListener know about the token's type, starting and ending positions.

private boolean parseKey(final CharSource source, final TokenEventListener event) {
int ch = source.nextSkipWhiteSpace();
event.start(TokenTypes.ATTRIBUTE_KEY_TOKEN, source.getIndex(), source);
boolean found = false;
switch(ch) {
case STRING_START_TOKEN:
final int strStartIndex = source.getIndex();
event.start(TokenTypes.STRING_TOKEN, strStartIndex + 1, source);
final int strEndIndex;
if (objectsKeysCanBeEncoded) {
strEndIndex = source.findEndOfEncodedString();
} else {
strEndIndex = source.findEndString();
}
found = true;
event.end(TokenTypes.STRING_TOKEN, strEndIndex, source);
break;
case OBJECT_END_TOKEN:
return true;
default:
throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
}
boolean done = source.findObjectEndOrAttributeSep();
if (!done && found) {
event.end(TokenTypes.ATTRIBUTE_KEY_TOKEN, source.getIndex(), source);
} else if (found && done) {
throw new UnexpectedCharacterException("Parsing key", "Not found", source);
}
return done;
}The parseKey method is defined in the JsonEventFastParser class of the io.nats.jparse.parser.event package.
Here is a step-by-step description of what the parseKey method does based on its body:
- It takes two parameters:
sourceof typeCharSourceandeventof typeTokenEventListener. - It retrieves the next character from the
sourcewhile skipping any whitespace. - It notifies the
eventthat a newATTRIBUTE_KEY_TOKENis being started, providing the index and the source. - It uses a switch statement to handle different cases for the retrieved character:
- If the character is
STRING_START_TOKEN, it means that a new string token is starting.- It notifies the
eventthat a newSTRING_TOKENis being started, providing the index plus one (to exclude theSTRING_START_TOKEN) and the source. - It determines the end index of the string token:
- If
objectsKeysCanBeEncodedis true, it uses thefindEndOfEncodedString()method of thesourceto locate the end of the encoded string. - If
objectsKeysCanBeEncodedis false, it uses thefindEndString()method of thesourceto locate the end of the string.
- If
- It sets
foundtotrueto indicate that a string token has been found. - It notifies the
eventthat theSTRING_TOKENis ending, providing the end index and the source.
- It notifies the
- If the character is
OBJECT_END_TOKEN, it means that the end of the object is reached.- It returns
trueto indicate that the parsing of the key is done.
- It returns
- If none of the above cases match, it throws an
UnexpectedCharacterExceptionwith a message indicating that an unexpected character is found in the key parsing, along with the source.
- If the character is
- It attempts to find the end of the object or the attribute separator in the
source, and assigns the result to thedonevariable. - If
doneisfalseandfoundistrue, it notifies theeventthat theATTRIBUTE_KEY_TOKENis ending, providing the current index and the source. - If
foundistrueanddoneistrue, it throws anUnexpectedCharacterExceptionwith a message indicating that the end of the key is not found, along with the source. - It returns the value of
done, indicating whether the parsing of the key is done or not.
The method parseKey is a part of the JsonEventFastParser class in the io.nats.jparse.parser.event package.
This method is responsible for parsing the key of a JSON attribute. It takes a CharSource object and a TokenEventListener object as parameters.
The method begins by skipping any whitespace characters in the source and then starts the attribute key token event. It then checks the next character in the source.
If the next character is a string start token, the method starts a string token event, determines the end index of the string, and sets the found flag to true. The method then ends the string token event.
If the next character is an object end token, the method returns true.
If none of the above conditions are met, the method throws an UnexpectedCharacterException with a relevant message.
Finally, the method checks if the parsing is done by finding the end of the object or the attribute separator in the source. If parsing is not yet done and the found flag is true, the method ends the attribute key token event. If parsing is done and the found flag is true, the method throws an UnexpectedCharacterException with a relevant message.
The method returns the value of the done variable, indicating whether the parsing of the key is completed or not.
private boolean parseValue(final CharSource source, final TokenEventListener event) {
int ch = source.nextSkipWhiteSpace();
event.start(TokenTypes.ATTRIBUTE_VALUE_TOKEN, source.getIndex(), source);
switch(ch) {
case OBJECT_START_TOKEN:
parseObject(source, event);
break;
case ARRAY_START_TOKEN:
parseArray(source, event);
break;
case TRUE_BOOLEAN_START:
parseTrue(source, event);
break;
case FALSE_BOOLEAN_START:
parseFalse(source, event);
break;
case NULL_START:
parseNull(source, event);
break;
case STRING_START_TOKEN:
parseString(source, event);
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
parseNumber(source, event);
break;
default:
throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, ch);
}
source.skipWhiteSpace();
switch(source.getCurrentChar()) {
case OBJECT_END_TOKEN:
event.end(TokenTypes.ATTRIBUTE_VALUE_TOKEN, source.getIndex(), source);
return true;
case OBJECT_ATTRIBUTE_SEP:
event.end(TokenTypes.ATTRIBUTE_VALUE_TOKEN, source.getIndex(), source);
return false;
default:
throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, source.getCurrentChar());
}
}The parseValue method in the JsonEventFastParser class is responsible for parsing a JSON value from a given source and generating corresponding events through a TokenEventListener.
Here is a step-by-step description of what the parseValue method does based on its body:
-
The method starts by skipping any white space characters in the source and then notifies the event listener that a new attribute value token is about to be processed.
-
It reads the next character from the source and performs a switch case based on its value:
- If the character is the start of an object (
{), it calls theparseObjectmethod to parse the object. - If the character is the start of an array (
[), it calls theparseArraymethod to parse the array. - If the character is the start of a boolean true value (
true), it calls theparseTruemethod to parse the true value. - If the character is the start of a boolean false value (
false), it calls theparseFalsemethod to parse the false value. - If the character is the start of a null value (
null), it calls theparseNullmethod to parse the null value. - If the character is the start of a string (
"), it calls theparseStringmethod to parse the string. - If the character is a digit or a minus/plus sign (
0-9,-,+), it calls theparseNumbermethod to parse a number. - If none of the above cases match, it throws an
UnexpectedCharacterExceptionwith an error message.
- If the character is the start of an object (
-
After parsing the value, the method skips any remaining white space characters in the source.
-
It then performs another switch case based on the current character in the source:
- If the character is the end of an object (
}), it notifies the event listener that the attribute value token has ended and returnstrue. - If the character is the separator between object attributes (
:), it notifies the event listener that the attribute value token has ended and returnsfalse. - If none of the above cases match, it throws an
UnexpectedCharacterExceptionwith an error message.
- If the character is the end of an object (
This method is responsible for handling the main types of JSON values (objects, arrays, booleans, null, strings, and numbers) and generating appropriate events for each value type through the event listener.
The parseValue method in the JsonEventFastParser class is responsible for parsing a JSON value from a given CharSource and notifying a TokenEventListener with the parsed value.
First, it reads the next character from the source and skips any whitespace. It then notifies the event listener that it is starting to parse an attribute value token.
Based on the type of the character read, it performs the following actions:
- If the character is the start of an object token, it invokes the
parseObjectmethod. - If the character is the start of an array token, it invokes the
parseArraymethod. - If the character is the start of a
trueboolean token, it invokes theparseTruemethod. - If the character is the start of a
falseboolean token, it invokes theparseFalsemethod. - If the character is the start of a
nulltoken, it invokes theparseNullmethod. - If the character is the start of a string token, it invokes the
parseStringmethod. - If the character is a digit or a symbol related to numbers, it invokes the
parseNumbermethod. - If none of the above cases match, it throws an exception for encountering an unexpected character.
After parsing the value and skipping any whitespace, it checks the current character of the source. If it is the end of an object token, it notifies the event listener and returns true. If it is a comma separating object attributes, it notifies the event listener and returns false. If none of these cases match, it throws an exception for encountering an unexpected character.
Overall, the parseValue method efficiently parses and validates a JSON value, handling various types such as objects, arrays, booleans, null, numbers, and strings.

private void parseObject(final CharSource source, final TokenEventListener event) {
event.start(TokenTypes.OBJECT_TOKEN, source.getIndex(), source);
boolean done = false;
while (!done) {
done = parseKey(source, event);
if (!done)
done = parseValue(source, event);
}
if (source.getCurrentChar() != OBJECT_END_TOKEN) {
throw new UnexpectedCharacterException("Parsing Object", "Unexpected character", source, source.getCurrentCharSafe());
}
source.next();
event.end(TokenTypes.OBJECT_TOKEN, source.getIndex(), source);
}The parseObject method in the JsonEventFastParser class is used to parse a JSON object. Here's a step-by-step description of how the method works:
-
It starts by invoking the
startmethod of theTokenEventListenerwith the token typeOBJECT_TOKENto indicate the beginning of parsing an object. It also provides the index and the character source. -
It initializes a boolean variable
donetofalse, which will be used to determine when parsing is complete. -
It enters a while loop, which continues until
doneis true. This loop iteratively parses the key-value pairs within the JSON object. -
Inside the loop, it calls the
parseKeymethod to parse the key of the key-value pair. TheparseKeymethod is expected to return a boolean value indicating whether the key parsing is complete. -
If the
parseKeymethod returnsfalse, it means the key parsing is not yet complete, so it calls theparseValuemethod to parse the value of the key-value pair. -
After parsing the key and value, it checks if the current character is the end of the object token (
OBJECT_END_TOKEN). If it's not, it throws anUnexpectedCharacterException, indicating that an unexpected character was found when parsing the JSON object. -
If the current character is the end of the object token, it moves to the next character in the source by invoking the
nextmethod. -
Finally, it invokes the
endmethod of theTokenEventListenerwith the token typeOBJECT_TOKENto indicate the end of parsing an object. It also provides the index and the character source.
This method essentially handles the parsing of a JSON object by calling helper methods to parse the key-value pairs and verifying the end of the object token.
The parseObject method in the class io.nats.jparse.parser.event.JsonEventFastParser is responsible for parsing a JSON object from a given input source.
The method starts by notifying the event listener that an object token is being parsed. It then enters a loop, where it alternates between parsing a key and parsing a value until the end of the object is reached.
After the loop, the method checks if the last character of the input source is the expected object end token. If it's not, an UnexpectedCharacterException is thrown.
Finally, the method notifies the event listener that the parsing of the object is complete.

The JsonEventAbstractParser class provides shared code for event parsers. It is an abstract class that implements the JsonEventParser and JsonParser interfaces. This class serves as a base for implementing event-based JSON parsers.
public List scan(final CharSource source)
@Override
public List<Token> scan(final CharSource source) {
tokenList = new TokenList();
this.parseWithEvents(source, base);
return tokenList;
}This method is defined in the io.nats.jparse.parser.event.JsonEventAbstractParser class.
-
source: TheCharSourceobject representing the input source to be scanned.
-
List<Token>: The list of tokens generated by the scan process.
- Create a new
TokenListobject to store the generated tokens. - Call the
parseWithEventsmethod passing thesourceandbaseparameters, along with the current instance of the class. This method is responsible for parsing the input source and generating events based on the JSON syntax. - Return the populated
tokenListwhich now contains the tokens generated during the parsing process.
The scan method is an overridden method in the JsonEventAbstractParser class. It accepts a CharSource object as a parameter and returns a list of Token objects.
Within the method, a new instance of TokenList is created. The parseWithEvents method is called with the provided source and base parameters. This method is responsible for parsing the source and generating appropriate events based on the JSON structure.
Once the parsing is completed, the tokenList, which contains the generated Token objects, is returned. The Token objects represent the different elements found in the JSON structure, such as keys, values, arrays, and objects.

The JsonEventStrictParser class is a strict JSON parser that extends the JsonEventAbstractParser class. It provides functionality for parsing JSON data in a strict manner.
public void parseWithEvents(CharSource source, final TokenEventListener event)
@Override
public void parseWithEvents(CharSource source, final TokenEventListener event) {
int ch = source.nextSkipWhiteSpace();
switch(ch) {
case ParseConstants.OBJECT_START_TOKEN:
parseObject(source, event);
break;
case ParseConstants.ARRAY_START_TOKEN:
parseArray(source, event);
break;
case ParseConstants.TRUE_BOOLEAN_START:
parseTrue(source, event);
break;
case ParseConstants.FALSE_BOOLEAN_START:
parseFalse(source, event);
break;
case ParseConstants.NULL_START:
parseNull(source, event);
break;
case ParseConstants.STRING_START_TOKEN:
parseString(source, event);
break;
case ParseConstants.NUM_0:
case ParseConstants.NUM_1:
case ParseConstants.NUM_2:
case ParseConstants.NUM_3:
case ParseConstants.NUM_4:
case ParseConstants.NUM_5:
case ParseConstants.NUM_6:
case ParseConstants.NUM_7:
case ParseConstants.NUM_8:
case ParseConstants.NUM_9:
case ParseConstants.MINUS:
case ParseConstants.PLUS:
parseNumber(source, event);
break;
default:
throw new UnexpectedCharacterException("Scanning JSON", "Unexpected character", source, (char) ch);
}
source.checkForJunk();
}The parseWithEvents method in the JsonEventStrictParser class is responsible for parsing a JSON document step by step and triggering events based on the encountered tokens.
Here is a step-by-step description of what this method does:
-
It takes two parameters:
source, which is theCharSource(a character source providing the JSON document), andevent, which is theTokenEventListener(to handle events). -
It reads the next character from the
sourceand skips any leading whitespace. -
It uses a switch statement to determine the type of token based on the read character:
-
If the token is an object start token (
{), it calls theparseObjectmethod, passing thesourceandeventas parameters. -
If the token is an array start token (
[), it calls theparseArraymethod, passing thesourceandeventas parameters. -
If the token is a
trueboolean start token, it calls theparseTruemethod, passing thesourceandeventas parameters. -
If the token is a
falseboolean start token, it calls theparseFalsemethod, passing thesourceandeventas parameters. -
If the token is a
nullstart token, it calls theparseNullmethod, passing thesourceandeventas parameters. -
If the token is a string start token (
"), it calls theparseStringmethod, passing thesourceandeventas parameters. -
If the token is a numeric digit or a minus/plus sign, it calls the
parseNumbermethod, passing thesourceandeventas parameters. -
If the token does not match any of the above cases, it throws an
UnexpectedCharacterExceptionwith a descriptive error message.
-
-
After parsing the token, it checks for any additional junk characters in the
sourceand throws an exception if any leftovers are found.
In summary, the parseWithEvents method reads each character from the input JSON document, identifies its type, and calls the appropriate parsing method. It also ensures that there are no unexpected characters or junk at the end of the document.
The parseWithEvents method in the JsonEventStrictParser class is used to parse a JSON input using events.
Here's what the method does:
- It reads the next character from the input source and skips any whitespace.
- It then checks the type of the character and performs the appropriate action:
- If the character represents the start of an object ('{'), it calls the
parseObjectmethod. - If the character represents the start of an array ('['), it calls the
parseArraymethod. - If the character represents the start of a
trueboolean value ('t'), it calls theparseTruemethod. - If the character represents the start of a
falseboolean value ('f'), it calls theparseFalsemethod. - If the character represents the start of a
nullvalue ('n'), it calls theparseNullmethod. - If the character represents the start of a string ('"'), it calls the
parseStringmethod. - If the character represents a number (0-9, '-', '+'), or a decimal point, it calls the
parseNumbermethod. - If none of the above cases match, it throws an
UnexpectedCharacterException.
- If the character represents the start of an object ('{'), it calls the
- After parsing the value, it checks for any additional junk characters in the input source using the
checkForJunkmethod.
Overall, the parseWithEvents method allows for parsing a JSON input by handling different JSON types and invoking appropriate event callbacks for each type.

private void parseArray(final CharSource source, final TokenEventListener event) {
levelCheck(source);
event.start(TokenTypes.ARRAY_TOKEN, source.getIndex(), source);
boolean done = false;
while (!done) {
done = parseArrayItem(source, event);
if (!done) {
done = source.findCommaOrEndForArray();
}
}
event.end(TokenTypes.ARRAY_TOKEN, source.getIndex(), source);
}The parseArray method is a private method defined in the io.nats.jparse.parser.event.JsonEventStrictParser class. It takes two parameters: source of type CharSource and event of type TokenEventListener.
Here is a step-by-step description of what the parseArray method does based on its body:
- It starts by calling a method called
levelCheckpassing thesourceparameter. This method performs some checks related to the level of the parsing. - It then calls the
startmethod on theeventparameter, passingTokenTypes.ARRAY_TOKEN,source.getIndex()(current index in thesource), andsourceitself. This indicates the start of an array token to theTokenEventListener. - It initializes a boolean variable called
doneasfalse. - It enters a
whileloop that continues untildoneistrue. - Inside the loop, it calls a method called
parseArrayItempassing thesourceandeventparameters. This method is responsible for parsing each item within the array. - After the
parseArrayItemmethod returns, it checks if thedonevariable is stillfalse.- If
doneis stillfalse, it calls thefindCommaOrEndForArraymethod on thesourceto find the next comma or end of the array. - If
doneistrue, it exits thewhileloop.
- If
- After the
whileloop, it calls theendmethod on theeventparameter, passingTokenTypes.ARRAY_TOKEN,source.getIndex()(current index in thesource), andsourceitself. This indicates the end of the array token to theTokenEventListener.
In summary, the parseArray method is responsible for parsing an array from the source using the parseArrayItem method and notifying the TokenEventListener about the start and end of the array token.
The parseArray method is a private method defined in the JsonEventStrictParser class. It is responsible for parsing an array from a given CharSource while notifying an TokenEventListener about the encountered events.
Here is a breakdown of what the method does:
- It performs a level check on the provided
CharSource. - It notifies the
TokenEventListenerthat the start of an array token has been encountered. - A loop is initiated until the parsing of the array is complete.
- Inside the loop, it calls the
parseArrayItemmethod to parse each item in the array. TheTokenEventListeneris notified about the parsed item. - After parsing an item, it checks if the parsing is complete by calling the
findCommaOrEndForArraymethod on theCharSource. If a comma is found, the loop continues to parse the next item. If the end of the array is encountered, the loop is terminated. - Finally, it notifies the
TokenEventListenerthat the end of the array token has been encountered, providing the index of theCharSource.
In summary, the parseArray method is responsible for parsing an array from a CharSource and notifying the TokenEventListener about the start and end of the array token, as well as each individual array item.

private boolean parseArrayItem(CharSource source, final TokenEventListener event) {
char startChar = source.getCurrentChar();
int ch = source.nextSkipWhiteSpace();
switch(ch) {
case ParseConstants.OBJECT_START_TOKEN:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseObject(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case ParseConstants.ARRAY_START_TOKEN:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseArray(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case ParseConstants.TRUE_BOOLEAN_START:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseTrue(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case ParseConstants.FALSE_BOOLEAN_START:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseFalse(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case ParseConstants.NULL_START:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseNull(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case ParseConstants.STRING_START_TOKEN:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseString(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
break;
case ParseConstants.NUM_0:
case ParseConstants.NUM_1:
case ParseConstants.NUM_2:
case ParseConstants.NUM_3:
case ParseConstants.NUM_4:
case ParseConstants.NUM_5:
case ParseConstants.NUM_6:
case ParseConstants.NUM_7:
case ParseConstants.NUM_8:
case ParseConstants.NUM_9:
case ParseConstants.MINUS:
case ParseConstants.PLUS:
event.start(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
parseNumber(source, event);
event.end(TokenTypes.ARRAY_ITEM_TOKEN, source.getIndex(), source);
if (source.getCurrentChar() == ParseConstants.ARRAY_END_TOKEN || source.getCurrentChar() == ParseConstants.ARRAY_SEP) {
if (source.getCurrentChar() == ParseConstants.ARRAY_END_TOKEN) {
source.next();
return true;
}
}
break;
case ParseConstants.ARRAY_END_TOKEN:
if (startChar == ParseConstants.ARRAY_SEP) {
throw new UnexpectedCharacterException("Parsing Array Item", "Trailing comma", source, (char) ch);
}
source.next();
return true;
default:
throw new UnexpectedCharacterException("Parsing Array Item", "Unexpected character", source, (char) ch);
}
return false;
}The parseArrayItem method in the JsonEventStrictParser class is responsible for parsing individual items in a JSON array. Here is a step-by-step description of what the method does:
-
The method takes two parameters:
source, which is the input source containing the JSON array, andevent, which is the event listener that will be notified of parsing events. -
It starts by getting the current character from the source and storing it in the
startCharvariable. -
The method then calls the
nextSkipWhitespacemethod on the input source to skip any whitespace characters and get the next character in the source, which is stored in thechvariable. -
The method enters a switch statement based on the value of
ch. -
If the value of
chis equal toParseConstants.OBJECT_START_TOKEN(which represents the start of a JSON object), it notifies the event listener that an array item has started, and then calls theparseObjectmethod to parse the JSON object. After the object is parsed, it notifies the event listener that the array item has ended. -
If the value of
chis equal toParseConstants.ARRAY_START_TOKEN(which represents the start of another JSON array), it follows a similar process as in step 5, but calls theparseArraymethod instead to parse the array. -
If the value of
chis equal toParseConstants.TRUE_BOOLEAN_STARTorParseConstants.FALSE_BOOLEAN_START(which represent the start of a boolean value), it again follows a similar process as in step 5, but calls theparseTrueorparseFalsemethod respectively to parse the boolean value. -
If the value of
chis equal toParseConstants.NULL_START(which represents the start of a null value), it follows a similar process as in step 5, but calls theparseNullmethod to parse the null value. -
If the value of
chis equal toParseConstants.STRING_START_TOKEN(which represents the start of a string value), it follows a similar process as in step 5, but calls theparseStringmethod to parse the string value. -
If the value of
chis one ofParseConstants.NUM_0,ParseConstants.NUM_1, ...,ParseConstants.NUM_9,ParseConstants.MINUS, orParseConstants.PLUS(which represent the start of a number), it again follows a similar process as in step 5, but calls theparseNumbermethod to parse the number value. It then checks if the current character in the source is either the end of the JSON array or a comma separator. If it is, it checks if the current character is the end of the JSON array, and if so, it returnstrue(indicating that the parsing of the array is complete). -
If the value of
chis equal toParseConstants.ARRAY_END_TOKEN, it checks if thestartCharvariable is equal toParseConstants.ARRAY_SEP(which represents a trailing comma in the array). If it is, it throws an exception indicating that a trailing comma is not allowed. Otherwise, it moves to the next character in the source and returnstrue(indicating that the parsing of the array is complete). -
If none of the above cases match, it throws an exception indicating that an unexpected character was encountered while parsing the array item.
-
Finally, the method returns
falseto indicate that the parsing of the array item is not complete.
The method parseArrayItem is used to parse an item within a JSON array. It takes a CharSource and a TokenEventListener as parameters.
First, it retrieves the current character from the CharSource and skips any whitespace characters. Then, it enters a switch statement based on the retrieved character.
- If the character indicates the start of an object (
{), it invokes theparseObjectmethod to further parse the object, and notifies theTokenEventListenerof the start and end of the array item. - If the character indicates the start of another array (
[), it invokes theparseArraymethod to further parse the nested array, and notifies theTokenEventListenerof the start and end of the array item. - If the character indicates the start of a boolean
true, it invokes theparseTruemethod to parse the boolean value, and notifies theTokenEventListenerof the start and end of the array item. - If the character indicates the start of a boolean
false, it invokes theparseFalsemethod to parse the boolean value, and notifies theTokenEventListenerof the start and end of the array item. - If the character indicates the start of a
nullvalue, it invokes theparseNullmethod to parse the value, and notifies theTokenEventListenerof the start and end of the array item. - If the character indicates the start of a string (
"), it invokes theparseStringmethod to parse the string value, and notifies theTokenEventListenerof the start and end of the array item. - If the character indicates the start of a number (
0-9, minus sign, plus sign), it invokes theparseNumbermethod to parse the number value, and notifies theTokenEventListenerof the start and end of the array item. It then checks if the current character is either the end of the array or a separator, and if so, it returnstrueto indicate that the parsing of the array item is complete. - If the character indicates the end of the array (
]), it checks if the previous character was a separator. If so, it throws an exception for a trailing comma. Otherwise, it advances to the next character and returnstrueto indicate the end of the parsing.
If none of the above cases match, it throws an exception for an unexpected character in the array item.
Finally, if the parsing is not complete, it returns false.
private void parseNumber(final CharSource source, final TokenEventListener event) {
final int startIndex = source.getIndex();
final NumberParseResult numberParse = source.findEndOfNumber();
final int tokenType = numberParse.wasFloat() ? TokenTypes.FLOAT_TOKEN : TokenTypes.INT_TOKEN;
event.start(tokenType, startIndex, source);
event.end(tokenType, numberParse.endIndex(), source);
}The parseNumber method in the JsonEventStrictParser class is responsible for parsing a number from a given character source and notifying the event listener about the parsed token.
Here is a step-by-step description of what the parseNumber method does:
- Retrieve the current index in the character source using
source.getIndex()and store it instartIndexvariable. - Utilize the
findEndOfNumbermethod from theCharSourceclass to locate the end position of the number being parsed. This method returns aNumberParseResultobject, which contains information about whether the number was parsed as a float or an integer. - Determine the token type based on whether the number was parsed as a float or an integer. If it was a float, assign
TokenTypes.FLOAT_TOKENto thetokenTypevariable. Otherwise, assignTokenTypes.INT_TOKEN. - Notify the event listener that parsing of the number is starting by invoking
event.start()method and passing thetokenType,startIndex, and the original source as arguments. - Notify the event listener that parsing of the number has ended by invoking
event.end()method and passing thetokenType, the end index of the parsed number obtained fromnumberParse.endIndex(), and the original source as arguments.
Overall, the parseNumber method scans the character source for numbers, determines their types, and informs the event listener of the start and end positions of the parsed numbers using the appropriate token types.
The method parseNumber in class JsonEventStrictParser is used to parse a number from a CharSource object.
- It first gets the starting index of the number from the
CharSourceusingsource.getIndex(). - Then, it uses the
findEndOfNumbermethod on theCharSourceto determine the end of the number and obtain aNumberParseResultobject. - Based on whether the number was a float or an integer, it assigns the appropriate token type
TokenTypes.FLOAT_TOKENorTokenTypes.INT_TOKEN. - It then calls the
startandendmethods on theTokenEventListenerobjecteventto notify the start and end of the number token, passing the token type, start index, end index, and theCharSourceobject.

private boolean parseKey(final CharSource source, final TokenEventListener event) {
final char startChar = source.getCurrentChar();
int ch = source.nextSkipWhiteSpace();
event.start(TokenTypes.ATTRIBUTE_KEY_TOKEN, source.getIndex(), source);
boolean found = false;
switch(ch) {
case ParseConstants.STRING_START_TOKEN:
final int strStartIndex = source.getIndex();
event.start(TokenTypes.STRING_TOKEN, strStartIndex + 1, source);
final int strEndIndex;
if (objectsKeysCanBeEncoded) {
strEndIndex = source.findEndOfEncodedString();
} else {
strEndIndex = source.findEndString();
}
found = true;
event.end(TokenTypes.STRING_TOKEN, strEndIndex, source);
break;
case ParseConstants.OBJECT_END_TOKEN:
if (startChar == ParseConstants.OBJECT_ATTRIBUTE_SEP) {
throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
}
return true;
default:
throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
}
boolean done = source.findObjectEndOrAttributeSep();
if (!done && found) {
event.end(TokenTypes.ATTRIBUTE_KEY_TOKEN, source.getIndex(), source);
} else if (found && done) {
throw new UnexpectedCharacterException("Parsing key", "Not found", source);
}
return done;
}This method is defined in the JsonEventStrictParser class within the io.nats.jparse.parser.event package. It takes two parameters: a CharSource object named source and a TokenEventListener object named event. The method returns a boolean value.
- Get the starting character from the
sourceobject and store it in a local variable calledstartChar.
- Call the
nextSkipWhiteSpace()method on thesourceobject to move to the next non-whitespace character. - Store the resulting character in a local variable named
ch.
- Call the
start()method on theeventobject, passingTokenTypes.ATTRIBUTE_KEY_TOKENas the token type, the current index of thesource, and thesourceobject itself.
- Use a switch statement to check the type of the character
ch.
- If
chis equal toParseConstants.STRING_START_TOKEN:- Store the current index of the
sourceobject in a local variable calledstrStartIndex. - Call the
start()method on theeventobject, passingTokenTypes.STRING_TOKENas the token type, (strStartIndex + 1) as the start index, and thesourceobject itself. - Determine the end index of the string based on the value of
objectsKeysCanBeEncoded. - If
objectsKeysCanBeEncodedis true, call thefindEndOfEncodedString()method on thesourceobject to find the end index of the string. - If
objectsKeysCanBeEncodedis false, call thefindEndString()method on thesourceobject to find the end index of the string. - Set the
foundvariable to true. - Call the
end()method on theeventobject, passingTokenTypes.STRING_TOKENas the token type, the end index of the string, and thesourceobject itself.
- Store the current index of the
- If
chis equal toParseConstants.OBJECT_END_TOKEN:- Check if the
startCharis equal toParseConstants.OBJECT_ATTRIBUTE_SEP. - If true, throw an
UnexpectedCharacterExceptionwith the message "Unexpected character found" and thesourceobject. - Return true.
- Check if the
- If none of the above cases match, throw an
UnexpectedCharacterExceptionwith the message "Unexpected character found" and thesourceobject.
- Call the
findObjectEndOrAttributeSep()method on thesourceobject and store the result in a boolean variable nameddone.
- If
doneis false andfoundis true, call theend()method on theeventobject, passingTokenTypes.ATTRIBUTE_KEY_TOKENas the token type, the current index of thesource, and thesourceobject itself.
- If
foundis true anddoneis true, throw anUnexpectedCharacterExceptionwith the message "Not found" and thesourceobject.
- This method returns the value of the
donevariable, indicating whether the parsing is done or not.
The parseKey method in the JsonEventStrictParser class is used to parse a key from a JSON input using a strict parsing approach.
Here's a step-by-step breakdown of how the method works:
-
It takes a
CharSourceobject, which represents the source of characters to be parsed, and aTokenEventListenerobject, which listens to the events generated during parsing. -
The method starts by capturing the current character of the source and reads the next character, skipping whitespace.
-
It notifies the event listener that it is starting to parse an attribute key token.
-
It evaluates the type of character read:
-
If the character is a string start token (
"), it signifies the start of a string. The method then captures the starting index of the string and notifies the event listener that it is starting to parse a string token. It then identifies the end of the string, considering whether object keys can be encoded or not, and notifies the event listener that it has ended the string token. -
If the character is an object end token (
}), it checks if the start character of the key is the object attribute separator (:). If it is not, it throws anUnexpectedCharacterExceptionindicating that an unexpected character was found while parsing the key. If it is, the method returnstrue, indicating that the parsing of the key is complete. -
If none of the above conditions are met, it throws an
UnexpectedCharacterExceptionindicating that an unexpected character was found while parsing the key.
-
-
If the parsing is not yet complete and a valid key was found, the method attempts to find either the end of the object or the attribute separator.
-
If the parsing is not yet complete, but a valid key was found, the method notifies the event listener that it has ended the attribute key token.
-
If the parsing is complete but a valid key was found, it throws an
UnexpectedCharacterExceptionindicating that the key was not found. -
Finally, the method returns whether the parsing is complete or not.
This method is useful for parsing individual keys from a JSON input and generating events for further processing.
private boolean parseValue(final CharSource source, final TokenEventListener event) {
int ch = source.nextSkipWhiteSpace();
event.start(TokenTypes.ATTRIBUTE_VALUE_TOKEN, source.getIndex(), source);
switch(ch) {
case ParseConstants.OBJECT_START_TOKEN:
parseObject(source, event);
break;
case ParseConstants.ARRAY_START_TOKEN:
parseArray(source, event);
break;
case ParseConstants.TRUE_BOOLEAN_START:
parseTrue(source, event);
break;
case ParseConstants.FALSE_BOOLEAN_START:
parseFalse(source, event);
break;
case ParseConstants.NULL_START:
parseNull(source, event);
break;
case ParseConstants.STRING_START_TOKEN:
parseString(source, event);
break;
case ParseConstants.NUM_0:
case ParseConstants.NUM_1:
case ParseConstants.NUM_2:
case ParseConstants.NUM_3:
case ParseConstants.NUM_4:
case ParseConstants.NUM_5:
case ParseConstants.NUM_6:
case ParseConstants.NUM_7:
case ParseConstants.NUM_8:
case ParseConstants.NUM_9:
case ParseConstants.MINUS:
case ParseConstants.PLUS:
parseNumber(source, event);
break;
default:
throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, ch);
}
source.skipWhiteSpace();
switch(source.getCurrentChar()) {
case ParseConstants.OBJECT_END_TOKEN:
event.end(TokenTypes.ATTRIBUTE_VALUE_TOKEN, source.getIndex(), source);
return true;
case ParseConstants.OBJECT_ATTRIBUTE_SEP:
event.end(TokenTypes.ATTRIBUTE_VALUE_TOKEN, source.getIndex(), source);
return false;
default:
throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, source.getCurrentChar());
}
}The parseValue method in the JsonEventStrictParser class is used to parse a single JSON value from the input source.
Here is a step-by-step description of what the method is doing based on its body:
-
The method starts by reading the next character from the input source and skipping any white space characters.
-
It then notifies the token event listener that a new attribute value token has started.
-
The method enters a switch case based on the value of the current character: a. If the current character is the start of an object ('{'), it calls the
parseObjectmethod to parse the object. b. If the current character is the start of an array ('['), it calls theparseArraymethod to parse the array. c. If the current character is the start of the true boolean value ('t'), it calls theparseTruemethod to parse the boolean value true. d. If the current character is the start of the false boolean value ('f'), it calls theparseFalsemethod to parse the boolean value false. e. If the current character is the start of the null value ('n'), it calls theparseNullmethod to parse the null value. f. If the current character is the start of a string ('"'), it calls theparseStringmethod to parse the string value. g. If the current character is a number or a minus or plus sign, it calls theparseNumbermethod to parse the numeric value. h. If none of the above cases match, it throws anUnexpectedCharacterExceptionwith an error message indicating that an unexpected character was encountered while parsing the value. -
After parsing the value, the method skips any white space characters in the input source.
-
The method then enters another switch case based on the current character in the input source: a. If the current character is the end of an object ('}'), it notifies the token event listener that the attribute value token has ended and returns
true. b. If the current character is the object attribute separator (','), it notifies the token event listener that the attribute value token has ended and returnsfalse. c. If none of the above cases match, it throws anUnexpectedCharacterExceptionwith an error message indicating that an unexpected character was encountered while parsing the value.
In summary, the parseValue method in the JsonEventStrictParser class is responsible for parsing a single JSON value from the input source and notifying the token event listener about the start and end of the value token.
The parseValue method in the JsonEventStrictParser class is responsible for parsing a JSON value from a given source and notifying the token event listener about the parsed value.
The method starts by skipping any white space characters and then starts the parsing by identifying the type of the value based on the first character. It uses a switch statement to handle different types of values such as objects, arrays, booleans, null, strings, and numbers.
After parsing the value, it skips any remaining white space characters and checks the next character to determine the end of the value. If the next character is an object closing token (}), it notifies the token event listener and returns true. If the next character is an object attribute separator (:), it notifies the token event listener and returns false.
If the next character does not match any of the expected values, it throws an UnexpectedCharacterException with an appropriate error message.
Overall, the parseValue method is a critical part of the JSON parsing process and is responsible for parsing different types of JSON values and notifying the token event listener accordingly.

private void parseObject(final CharSource source, final TokenEventListener event) {
levelCheck(source);
event.start(TokenTypes.OBJECT_TOKEN, source.getIndex(), source);
boolean done = false;
while (!done) {
done = parseKey(source, event);
if (!done)
done = parseValue(source, event);
}
if (source.getCurrentChar() != ParseConstants.OBJECT_END_TOKEN) {
throw new UnexpectedCharacterException("Parsing Object", "Unexpected character", source, source.getCurrentCharSafe());
}
source.next();
event.end(TokenTypes.OBJECT_TOKEN, source.getIndex(), source);
}The method parseObject is defined in the class io.nats.jparse.parser.event.JsonEventStrictParser. It takes two parameters: source, which is of type CharSource, and event, which is of type TokenEventListener.
Here is a step-by-step description of what the method parseObject is doing:
- It performs a level check, which is not explained in the given code snippet.
- It starts the
OBJECT_TOKENevent by callingevent.start()method, passing the token type, the index of the source, and the source itself as parameters. - It initializes a boolean variable called
donetofalse. - It enters a while loop that continues until
doneis true. This loop is used to parse the key-value pairs of the object. - Inside the loop, it calls the
parseKeymethod passing thesourceandeventas arguments, and assigns the returned value todone. - If
parseKeydid not parse a key successfully, it calls theparseValuemethod passing thesourceandeventas arguments, and assigns the returned value todone. - If
source.getCurrentChar()is not theOBJECT_END_TOKEN(which indicates the end of the object), it throws anUnexpectedCharacterException. The exception message states that it was parsing an object and encountered an unexpected character. It also includes thesourceand the current character as additional information. - It advances the
sourceto the next character by callingsource.next(). - It ends the
OBJECT_TOKENevent by callingevent.end()method, passing the token type, the index of the source, and the source itself as parameters.
The method parseObject is responsible for parsing an object in the JSON input, iterating over its key-value pairs, and notifying the TokenEventListener about the start and end of the object.
The parseObject method is used to parse a JSON object string. It takes in a source input and a token event listener as parameters.
The method starts by performing a level check to ensure the input is valid. It then calls the event.start method to notify the listener that a JSON object token has been encountered.
A while loop is used to efficiently parse the key-value pairs within the object. Inside the loop, it first calls parseKey method to parse the key and notifies the event listener. If the key parsing is not yet done, it then calls parseValue method to parse the corresponding value and notifies the listener. This process continues until all key-value pairs have been parsed.
After the object's closing token is encountered, the method checks if it matches the expected object end token. If it doesn't, an exception is thrown. Otherwise, it calls source.next() to move the cursor to the next character and calls event.end to notify the listener that the object parsing is complete.
In summary, the parseObject method reads a JSON object string, validates its structure, parses its key-value pairs, and notifies an event listener about the start and end of the object token.

private void levelCheck(CharSource source) {
nestLevel++;
if (nestLevel > ParseConstants.NEST_LEVEL) {
throw new UnexpectedCharacterException("Next level violation", "Too many levels " + nestLevel, source);
}
}The method levelCheck in the JsonEventStrictParser class is responsible for checking the nesting level of a JSON document. Here is a step-by-step description of what this method does:
-
It receives a
CharSourceobject as a parameter, which represents the source of characters for parsing the JSON document. -
The method increments the
nestLevelvariable by one. This variable keeps track of the current nesting level in the JSON document. -
It checks if the
nestLevelis greater than a constant valueParseConstants.NEST_LEVEL. This constant represents the maximum allowed nesting level in the JSON document. -
If the
nestLevelexceeds the maximum allowed level, the method throws anUnexpectedCharacterExceptionwith the message "Next level violation" and additional information about exceeding the allowed level. -
If the
nestLevelis within the allowed limit, the method continues execution without any further action.
Overall, the levelCheck method ensures that the nesting level of the JSON document does not exceed a certain threshold and throws an exception if the limit is violated. This check helps maintain the integrity and reliability of the parsing process.
The levelCheck method in the JsonEventStrictParser class is responsible for checking the nesting level of a JSON document.
This method increments the nestLevel variable by one, indicating that a new nested level has been encountered. If the nestLevel exceeds the maximum allowed nesting level defined in ParseConstants.NEST_LEVEL, an UnexpectedCharacterException is thrown, indicating that the JSON document has violated the maximum nesting level constraint.
The exception message includes the details of the violation, specifically mentioning the current nestLevel, and the source of the JSON document where the violation occurred.


The EmployeeDeptMain class is a public class that serves as the entry point for the employee and department management system. It provides functionality for managing employees and departments within an organization.
public static void main(String... args) {
try {
final String json = getJson();
//final var engineeringEmployees = Path.atPath("departments[0].employees", json).asCollection().asArray();
final File file = new File("./src/test/resources/json/depts.json");
final RootNode rootNode = Json.toRootNode(Sources.fileSource(file));
final ArrayNode engineeringEmployees = Path.atPath("departments[0].employees", rootNode).asCollection().asArray();
final Node cindy = Path.atPath("[2]", engineeringEmployees);
final Node cindyName = Path.atPath("[2].firstName", engineeringEmployees);
final Node cindyId = Path.atPath(".id", cindy);
final Node manager = Path.atPath("[2].manager", engineeringEmployees);
System.out.println(" " + engineeringEmployees.toJsonString());
System.out.println(" " + cindy.toJsonString());
if (manager.asScalar().booleanValue()) {
System.out.printf("This employee %s is a manager %s \n", cindyName, manager);
}
if (cindyName.asScalar().equalsString("Cindy")) {
System.out.printf("The employee's name is Cindy %s \n", cindyId);
}
if (cindyName instanceof CharSequence) {
System.out.println("cirhyeName is a CharSequence");
}
if (cindyId instanceof Number) {
System.out.println("cindyId is a Number");
}
if (engineeringEmployees instanceof List) {
System.out.println("engineeringEmployees is a List " + engineeringEmployees.getClass().getName());
}
if (cindy instanceof Map) {
System.out.println("cindy is a Map " + cindy.getClass().getName());
}
final Optional<ObjectNode> rick = engineeringEmployees.stream().map(node -> node.asCollection().asObject()).filter(objectNode -> objectNode.getString("firstName").equals("Rick")).findFirst();
rick.ifPresent(node -> {
System.out.println("Found " + node);
exploreNode(node);
});
final Optional<ObjectNode> rick2 = engineeringEmployees.findObjectNode(objectNode -> objectNode.getString("firstName").equals("Rick"));
rick2.ifPresent(node -> {
System.out.println("Found " + node);
exploreNode(node);
});
final List<Employee> employees = engineeringEmployees.mapObjectNode(on -> new Employee(on.getString("firstName"), on.getString("lastName"), on.getString("dob"), on.getBoolean("manager"), on.getInt("id"), on.getInt("managerId")));
employees.forEach(System.out::println);
final ArrayNode departmentsNode = Path.atPath("departments", json).asCollection().asArray();
final List<Department> departments = departmentsNode.mapObjectNode(on -> new Department(on.getString("departmentName"), on.getArrayNode("employees").mapObjectNode(en -> new Employee(en.getString("firstName"), en.getString("lastName"), en.getString("dob"), en.getBoolean("manager"), en.getInt("id"), en.getInt("managerId")))));
departments.forEach(System.out::println);
parseBadJson();
} catch (Exception ex) {
ex.printStackTrace();
}
}The main method in class io.nats.jparse.examples.EmployeeDeptMain performs the following steps:
- Calls the
getJson()method to retrieve a JSON string. - Creates a
Fileobject pointing to the JSON file located at "./src/test/resources/json/depts.json". - Converts the file into a
RootNodeusing theJson.toRootNode()method. - Retrieves the "employees" array from the "departments[0]" path in the
RootNodeand assigns it to theengineeringEmployeesvariable. - Retrieves the third object in the
engineeringEmployeesarray and assigns it to thecindyvariable. - Retrieves the value of the "firstName" property from the
cindynode and assigns it to thecindyNamevariable. - Retrieves the value of the "id" property from the
cindynode using a relative path and assigns it to thecindyIdvariable. - Retrieves the value of the "manager" property from the
engineeringEmployeesarray at index 2 and assigns it to themanagervariable. - Prints the
engineeringEmployeesarray in JSON format. - Prints the
cindynode in JSON format. - Checks if the
managernode is a boolean value and prints a message if it is. - Checks if the
cindyNamenode is equal to the string "Cindy" and prints a message if it is. - Checks if the
cindyNamenode is an instance ofCharSequenceand prints a message if it is. - Checks if the
cindyIdnode is an instance ofNumberand prints a message if it is. - Checks if the
engineeringEmployeesobject is an instance ofListand prints a message with its class name if it is. - Checks if the
cindyobject is an instance ofMapand prints a message with its class name if it is. - Uses stream operations to find the first object in
engineeringEmployeeswith "firstName" equal to "Rick" and assigns it to therickoptional object. If found, it prints the found node and callsexploreNode()method with the found node. - Uses the
findObjectNode()method to find the object inengineeringEmployeeswith "firstName" equal to "Rick". - Assigns the found node to the
rick2optional object. If found, it prints the found node and callsexploreNode()method with the found node. - Maps each object in
engineeringEmployeesto anEmployeeobject using the corresponding properties and collects them into a list. - Prints each
Employeeobject in theemployeeslist. - Retrieves the "departments" array from the JSON string and assigns it to the
departmentsNodevariable. - Maps each object in
departmentsNodeto aDepartmentobject using the corresponding properties and collects them into a list. - Prints each
Departmentobject in thedepartmentslist. - Calls the
parseBadJson()method. - Catches any exception that occurs during the execution and prints the stack trace.

private static void parseBadJson() {
//RootNode rootNode = toRootNode(niceJson("'hi mom"));
//RootNode rootNode = toRootNode(niceJson("['aabc', \n 'def', \n 123f3f.9]"));
//RootNode rootNode = toRootNode(niceJson("{'name':'rick', \n\n\n" +
// " 'age':19, 'height'=10}"));
}The method parseBadJson() defined in class io.nats.jparse.examples.EmployeeDeptMain is used to parse invalid JSON input.
Here are the steps involved in this method:
-
Commented code: The method body contains multiple lines of commented code. These lines represent different variations of invalid JSON inputs.
-
RootNode object creation: The commented lines instantiate a
RootNodeobject namedrootNode. However, since these lines are commented out, they do not execute. -
toRootNode()method: ThetoRootNode()method is called with an argument,niceJson(), which is used to simulate invalid JSON data. However, since these lines are commented out, thetoRootNode()method is not executed. -
niceJson()method: TheniceJson()method is not defined in the given code snippet. Therefore, it is not involved in the execution of theparseBadJson()method.
In summary, the parseBadJson() method is designed to illustrate the parsing of invalid JSON inputs. However, since all the relevant code is commented out, this method does not perform any actual JSON parsing in its current state.

private static void exploreNode(ObjectNode node) {
int id = node.getInt("id");
String name = node.getString("firstName");
String dob = node.getString("dob");
boolean isManager = node.getBoolean("manager");
int managerId = node.getInt("managerId");
System.out.printf("%d %s %s %s %d \n", id, name, dob, isManager, managerId);
final NumberNode idNode = node.getNumberNode("id");
final StringNode nameNode = node.getStringNode("firstName");
final StringNode dobNode = node.getStringNode("dob");
final BooleanNode isManagerNode = node.getBooleanNode("manager");
final NumberNode managerIdNode = node.getNumberNode("managerId");
System.out.printf("%s %s %s %s %s \n", idNode, nameNode, dobNode, isManagerNode, managerIdNode);
System.out.printf("%d %s %s %s %d \n", idNode.intValue(), nameNode.toString(), dobNode.toString(), isManagerNode.booleanValue(), managerIdNode.intValue());
}The exploreNode method is defined in the EmployeeDeptMain class in the package io.nats.jparse.examples. Here is a step-by-step description of what the method does:
-
The method takes an
ObjectNodeas a parameter, which is a JSON object representing an employee's details. -
The method extracts the values from specific fields of the JSON object using various
getmethods such asgetInt,getString, andgetBoolean. The extracted values are assigned to local variables. -
The method prints the extracted values using
System.out.printfmethod call in a formatted string. -
The method then retrieves the same values again but this time using the
getXNodemethods, whereXrepresents the type of each particular value (e.g.,getNumberNode,getStringNode). The retrieved values are assigned to variables of respective types (NumberNode,StringNode, etc.). -
The method prints the retrieved
XNodevalues usingSystem.out.printfmethod call in a formatted string. -
Finally, the method prints the converted values from the
XNodevariables to their primitive types (e.g.,intValue,toString,booleanValue) usingSystem.out.printfmethod call in a formatted string.

The Department class is a final Class that represents a department in an organization. It provides functionality to manage and manipulate department related information.
The CloudEventMain class is a public class that serves as the entry point for processing cloud events. It contains the main method that initializes and runs the cloud event processing logic.
public static void main(String... args) {
final File file = new File("./src/test/resources/cloudevents/glossaryEvent.json");
final ObjectNode objectNode = Json.toRootNode(Sources.fileSource(file)).asObject();
if (objectNode.getNode("subject").equalsContent("glossaryFeed")) {
final String id = objectNode.getString("id");
final String type = objectNode.getString("type");
final String data = Json.serializeToString(objectNode.getNode("data"));
System.out.printf("%s %s %s \n%s\n", "glossaryFeed", id, type, data);
}
}The main method in the CloudEventMain class is performing the following steps based on its body:
-
It defines a
Fileobject with the file path "./src/test/resources/cloudevents/glossaryEvent.json". -
It uses the
Sources.fileSourcemethod to read the contents of the file and converts it to anObjectNodeusing theJson.toRootNodemethod. -
It checks if the value of the "subject" field in the
objectNodeis equal to "glossaryFeed" using theequalsContentmethod. -
If the condition in step 3 is true, it retrieves the values of the "id", "type", and "data" fields from the
objectNode. -
It serializes the value of the "data" field to a JSON string using the
Json.serializeToStringmethod. -
It prints the values of "glossaryFeed", "id", "type", and "data" to the console using the
System.out.printfmethod. The values are formatted in the following format: "glossaryFeed id type data".
Please note that the actual execution of the code may have additional steps or error handling that is not mentioned in the provided code snippet.

The Employee class is a final class that represents an employee. It provides various methods and attributes to manage and retrieve information about an employee.

The Validation class is a public class used for implementing validation logic in software applications. It provides methods and functionality to validate various types of input data or user inputs. This class serves as a utility for performing validation checks and returning appropriate results or error messages.
public static void main(String... args) {
try {
final File file = new File("./src/test/resources/validation/");
System.out.println("Event Strict Parser");
final boolean showPass = false;
final boolean showFail = false;
validateParser(file, (JsonParser) Json.builder().setStrict(true).buildEventParser(), showFail, showPass);
System.out.println("Strict Parser");
final JsonParser jsonParser = Json.builder().setStrict(true).build();
validateParser(file, jsonParser, showFail, showPass);
} catch (Throwable ex) {
ex.printStackTrace();
}
}The main method defined in the io.nats.jparse.Validation class performs the following steps:
-
It begins by trying to execute the code within a try block.
-
It creates a new File object and assigns it the path "./src/test/resources/validation/".
-
It prints the message "Event Strict Parser" to the console.
-
It initializes two boolean variables, showPass and showFail, and assigns each a value of false.
-
It calls the validateParser method with the file object and a JsonParser object created using the Json.builder() method. The JsonParser is configured to use strict parsing. The showFail and showPass variables are also passed to the validateParser method.
-
It prints the message "Strict Parser" to the console.
-
It creates a new JsonParser object by calling the Json.builder() method again and configuring it to use strict parsing.
-
It calls the validateParser method again with the file object, the newly created JsonParser, and the showFail and showPass variables.
-
If any exception or error occurs during the execution of the try block, it is caught by the catch block.
-
If an exception or error is caught, it is printed to the console using the printStackTrace method.

private static void validateParser(File file, JsonParser jsonParser, boolean showFail, boolean showPass)
private static void validateParser(File file, JsonParser jsonParser, boolean showFail, boolean showPass) {
int[] result1 = validate(file, "y_", showFail, showPass, jsonParser);
int[] result2 = validate(file, "i_", showFail, showPass, jsonParser);
int[] result3 = validate(file, "n_", showFail, showPass, jsonParser);
System.out.printf("Passed Mandatory %d Failed %d \n", result1[0], result1[1]);
System.out.printf("Passed Optional %d Failed %d \n", result2[0], result2[1]);
System.out.printf("Passed Garbage %d Failed %d \n", result3[0], result3[1]);
}The method validateParser is defined in the class io.nats.jparse.Validation. It takes four parameters: file, jsonParser, showFail, and showPass.
The method has the following steps:
- It calls the
validatemethod with the parametersfile,"y_",showFail,showPass, andjsonParser. The result is stored in an integer arrayresult1. - It calls the
validatemethod again with the parametersfile,"i_",showFail,showPass, andjsonParser. The result is stored in an integer arrayresult2. - It calls the
validatemethod once more with the parametersfile,"n_",showFail,showPass, andjsonParser. The result is stored in an integer arrayresult3. - It prints the number of passed and failed validations for the "Mandatory" category using the values in
result1. - It prints the number of passed and failed validations for the "Optional" category using the values in
result2. - It prints the number of passed and failed validations for the "Garbage" category using the values in
result3.
The output will be in the following format:
Passed Mandatory <number of passed validations> Failed <number of failed validations>
Passed Optional <number of passed validations> Failed <number of failed validations>
Passed Garbage <number of passed validations> Failed <number of failed validations>
Please note that the actual values for the number of passed and failed validations will depend on the implementation of the validate method.

private static int[] validate(File file, String match, boolean showFail, boolean showPass, JsonParser jsonParser)
private static int[] validate(File file, String match, boolean showFail, boolean showPass, JsonParser jsonParser) {
try {
int pass = 0;
int error = 0;
for (File listFile : file.listFiles()) {
if (listFile.getName().startsWith(match)) {
final CharSource cs = Sources.fileSource(listFile);
final String jsonString = cs.toString();
//System.out.println("TESTING " + listFile);
try {
RootNode root = jsonParser.parse(jsonString);
if (showPass) {
System.out.println("PASS! " + listFile);
System.out.println(cs);
System.out.println();
}
pass++;
} catch (Exception ex) {
//ex.printStackTrace();
if (showFail) {
System.out.println("FAIL! " + listFile);
System.out.println(cs);
System.out.println();
}
error++;
}
}
}
return new int[] { pass, error };
} catch (Throwable ex) {
ex.printStackTrace();
}
return new int[] { -1, -1 };
}The validate method is a static method defined in the io.nats.jparse.Validation class. Here is a step-by-step description of what the method does:
-
It takes the following parameters as input:
-
file: AFileobject representing a directory containing files to validate. -
match: AStringused to match filenames in the directory. -
showFail: Abooleanindicating whether to show failure messages. -
showPass: Abooleanindicating whether to show success messages. -
jsonParser: AJsonParserobject used to parse the JSON data.
-
-
The method starts by initializing two variables:
passanderrorto keep track of the number of successful and failed validations, respectively. -
It then iterates over each
Fileobject in the directory using an enhanced for loop. -
Inside the loop, it checks if the filename of the current
Fileobject starts with thematchstring. -
If the filename matches, it creates a
CharSourceobject using thelistFileand reads its content into aStringvariablejsonString. -
It then tries to parse the
jsonStringusing the providedjsonParserobject. -
If the parsing is successful, it increments the
passvariable. -
If the
showPassflag istrue, it prints a success message along with thelistFileandCharSourceobjects. -
If the parsing fails and an exception is thrown, it increments the
errorvariable. -
If the
showFailflag istrue, it prints a failure message along with thelistFileandCharSourceobjects. -
After iterating through all the files in the directory, the method returns an
intarray containing the number of successful and failed validations. -
If any
Throwableis caught during the execution of the method, it prints the stack trace of the exception. -
If any exception or error occurs during the execution of the method, it returns an
intarray with-1for both the successful and failed validations.
That's a step-by-step description of what the validate method does based on its provided body.

The TestKeyLookUp class is a public class that provides functionality for looking up test keys.
void testStringKey()
@Test
void testStringKey() {
final JsonParser parser = Json.builder().build();
final String json1 = "'1'";
final String json2 = "{'1':{'2':1}}";
final Node key = getJsonRoot(parser, json1).getNode();
final ObjectNode map = getJsonRoot(parser, json2).getObjectNode();
final Optional<Node> value = map.getNode(key);
assertTrue(value.isPresent());
final Node innerMap = value.get();
assertTrue(innerMap instanceof ObjectNode);
final ObjectNode innerObject = (ObjectNode) innerMap;
final long v = innerObject.getLong("2");
assertEquals(1, v);
}The testStringKey method in the io.nats.jparse.TestKeyLookUp class is a unit test for the StringKey functionality. Here is a step-by-step description of what this method is doing:
- Creating a new instance of the
JsonParserby callingJson.builder().build(). - Defining two
Stringvariables,json1andjson2, containing the JSON strings "'1'" and "{'1':{'2':1}}" respectively. - Calling the
getJsonRootmethod, passing theJsonParserandjson1as arguments, to obtain the root node of the JSON fromjson1. Storing the result in aNodevariable calledkey. - Calling the
getJsonRootmethod again, passing theJsonParserandjson2as arguments, to obtain the root node of the JSON fromjson2. Storing the result in aObjectNodevariable calledmap. - Calling the
getNodemethod on themapobject, passing thekeyas the argument, to retrieve the value associated with the given key. Storing the result in anOptional<Node>variable calledvalue. - Asserting that
valueis present (i.e., not null). - Calling the
getmethod onvalueto retrieve the actualNodeobject. Storing the result in aNodevariable calledinnerMap. - Asserting that
innerMapis an instance ofObjectNode. - Casting
innerMaptoObjectNodeand storing the result in anObjectNodevariable calledinnerObject. - Calling the
getLongmethod oninnerObject, passing "2" as the argument, to retrieve the value associated with the key "2". Storing the result in alongvariable calledv. - Asserting that the value of
vis equal to 1.
The Json class provides static utility methods for working with JSON data. It includes methods for parsing JSON data into various data structures, converting data structures to JSON, and scanning JSON data for tokens.
public static String niceJson(String json) {
char[] chars = json.toCharArray();
StringBuilder sb = new StringBuilder(chars.length);
for (char c : chars) {
if (c == '\'') {
sb.append('"');
} else if (c == '`') {
sb.append('\\');
} else {
sb.append(c);
}
}
return sb.toString();
}
```## Path
The `Path` class provides utility methods for working with JSON paths. It includes methods for parsing JSON paths, looking up nodes at specified paths, and converting paths to `PathNode` objects. This class is used in conjunction with other classes such as `Node`, `Json`, and `PathNode` to manipulate and traverse JSON data.
### public static Node atPath(final PathNode path, final Node rootNode)
```java
public static Node atPath(final PathNode path, final Node rootNode) {
Iterator<PathElement> iterator = path.iterator();
Node node = rootNode;
PathElement pathElement = null;
try {
while (iterator.hasNext()) {
pathElement = iterator.next();
switch(node.type()) {
case OBJECT:
final ObjectNode objectNode = (ObjectNode) node;
final CharSequence key = pathElement.asKey().toCharSequence();
node = objectNode.getNode(key);
break;
case ARRAY:
final ArrayNode arrayNode = (ArrayNode) node;
node = arrayNode.getNodeAt(pathElement.asIndex().intValue());
break;
default:
if (node.isCollection()) {
node = node.asCollection().getNode(pathElement.asKey().toCharSequence());
} else {
throw new PathException("Looking up Path", "Path not found at " + path + " path element key " + pathElement.asKey().toString(), node.charSource(), node.rootElementToken().startIndex);
}
}
}
} catch (Exception ex) {
throw new IllegalStateException("Path not found at " + path + " path element index " + pathElement.value());
}
return node;
}The atPath method is a static method defined in the Path class in the io.nats.jparse package. This method is used to navigate and retrieve a specific node in a JSON structure based on a given path.
public static Node atPath(final PathNode path, final Node rootNode)-
path(type:PathNode): The path to be followed to retrieve the desired node. -
rootNode(type:Node): The root node of the JSON structure from which the desired node is to be retrieved.
-
Node: The node found at the given path.
- The method starts by obtaining an iterator for the given path.
- It then initializes the
nodevariable with therootNodeparameter. - A
pathElementvariable is also initialized to null.
The method then enters a try-catch block, where the main logic of the method is described:
- Inside a while loop, the method checks if there are more elements in the path using the iterator's
hasNext()method. - If there are more elements, it retrieves the next path element using the iterator's
next()method and assigns it to thepathElementvariable. - Based on the type of the current node, the method follows one of the three cases:
- If the node is of type
OBJECT, it casts the node to anObjectNode, retrieves the key from the path element, and uses it to get the corresponding node from the object using thegetNode(key)method. This new node is assigned to thenodevariable. - If the node is of type
ARRAY, it casts the node to anArrayNodeand retrieves the node at the index specified by the path element using thegetNodeAt(index)method. This new node is assigned to thenodevariable. - If none of the above cases match, it checks if the node is a collection using the
isCollection()method. If it is, it retrieves the node based on the path element's key using thegetNode(key)method. Otherwise, it throws aPathExceptionindicating that the path was not found.
- If the node is of type
- The while loop continues until all elements in the path have been processed.
If there is any exception thrown during the execution of the while loop, it is caught in the catch block:
- The catch block throws an
IllegalStateExceptionindicating that the path was not found based on thepathandpathElementparameters.
Finally, the method returns the node found at the given path.
Note: The specific implementation details of the Node and PathNode classes are not provided in this code snippet. The behavior of the method may vary depending on the actual implementation of these classes.

The BenchMark class is annotated with @State(value = Scope.Benchmark), which signifies that it represents a state object for benchmarking purposes. This class is intended to be used in benchmarking scenarios, providing a state for measuring the performance of methods or code snippets.
public static void main(String... args) throws Exception {
try {
JsonParser fastParser = Json.builder().setStrict(false).build();
fastParser.parse(doublesJsonData).asArray().getDoubleArray();
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("DONE");
//
// try {
// long startTime = System.currentTimeMillis();
//
// JsonParser fastParser = Json.builder().setStrict(false).build();
//
// for (int i = 0; i < 10_500_000; i++) {
//
// final ObjectNode objectNode = fastParser.parse(glossaryEvent).asObject();
// if (objectNode.getNode("subject").equalsContent("glossaryFeed")) {
// final String id = objectNode.getStringNode("id").toUnencodedString();
// final String type = objectNode.getStringNode("type").toUnencodedString();
// final String description = objectNode.getStringNode("description").toUnencodedString();
// final String data = Json.serializeToString(objectNode.getNode("data"));
//
// if (i % 1_000_000 == 0) {
// System.out.printf("Elapsed time %s %s \n", ((System.currentTimeMillis() - startTime) / 1000.0), data);
// }
// }
//
// final JsonIterator iter = JsonIterator.parse(glossaryEvent);
// final Map<String, Object> map = iter.read(mapTypeRefJI);
// if (map.get("subject").equals("glossaryFeed")) {
// final String id = (String) map.get("id");
// final String type = (String) map.get("type");
// final String description = (String) map.get("description");
// final String data = JsonStream.serialize(map.get("data"));
// if (i % 1_000_000 == 0) {
// System.out.printf("Elapsed time %s %s \n", ((System.currentTimeMillis() - startTime) / 1000.0), data);
// }
// }
// final HashMap<String, Object> map = mapper.readValue(glossaryEvent, mapTypeRef);
// if (map.get("subject").equals("glossaryFeed")) {
// final String id = (String) map.get("id");
// final String type = (String) map.get("type");
// final String description = (String) map.get("description");
// final String data = mapper.writeValueAsString(map.get("data"));
// }
//
//
// }
// System.out.println("Total Elapsed time " + ((System.currentTimeMillis() - startTime) / 1000.0));
//
// } catch (Exception ex) {
// ex.printStackTrace();
// }
}The main method in class io.nats.jparse.BenchMark is divided into multiple sections, each performing a different task. Let's break it down step by step:
-
The method begins with a try-catch block to handle any exceptions that may occur during execution.
-
Inside the try block, a
JsonParserobject namedfastParseris created using theJson.builder()method. ThesetStrict(false)method is called to configure the parser to be non-strict. -
The
fastParserobject then parses the JSON data stored in thedoublesJsonDatavariable. The parsed data is treated as an array and thegetDoubleArray()method is called to retrieve an array of doubles. -
If an exception occurs during parsing, it is caught in the catch block and the stack trace is printed.
-
After the catch block, the string "DONE" is printed to the console.
-
The code is then commented out, starting from
try { long startTime = System.currentTimeMillis();and ending withSystem.out.println("Total Elapsed time " + ((System.currentTimeMillis() - startTime) / 1000.0)); }. -
In the commented out code, a
startTimevariable is initialized with the current system time. -
Inside a loop that iterates 10,500,000 times, the following actions are performed:
a. The
glossaryEventis parsed by thefastParserobject and the result is treated as anObjectNode.b. If the
"subject"field of theobjectNodeis equal to"glossaryFeed", the following fields are extracted from theobjectNode:"id","type","description"and"data". Thedatafield is serialized as a string usingJson.serializeToString()method.c. If the loop index
iis a multiple of 1,000,000, the elapsed time sincestartTimeis printed to the console along with the serializeddata.d. The
glossaryEventis parsed byJsonIteratorand the result is stored in aMap<String, Object>.e. If the
"subject"field of themapis equal to"glossaryFeed", the following fields are extracted:"id","type","description"and"data". Thedatafield is serialized as a string usingJsonStream.serialize()method.f. If the loop index
iis a multiple of 1,000,000, the elapsed time sincestartTimeis printed to the console along with the serializeddata.g. The
glossaryEventis deserialized into aHashMap<String, Object>using an unspecifiedmapperobject andmapTypeRef.h. If the
"subject"field of themapis equal to"glossaryFeed", the following fields are extracted:"id","type","description"and"data". Thedatafield is serialized as a string usingmapper.writeValueAsString()method. -
Finally, the total elapsed time since
startTimeis calculated and printed to the console. -
If an exception occurs during execution, it is caught in the catch block and the stack trace is printed.
This is the step-by-step description of the main method based on its body.

// @Benchmark // public void cloudEventJsonIter(Blackhole bh) throws Exception
//
// @Benchmark
// public void cloudEventJsonIter(Blackhole bh) throws Exception{
// final JsonIterator iter = JsonIterator.parse(glossaryEvent);
// final Map<String, Object> map = iter.read(mapTypeRefJI);
// if (map.get("subject").equals("glossaryFeed")) {
// final String id = (String) map.get("id");
// final String type = (String) map.get("type");
// final String description = (String) map.get("description");
// final String data = JsonStream.serialize(map.get("data"));
// bh.consume(new Object[]{id, type, data, description});
// }
// }
//
// @Benchmark
// public void cloudEventJackson(Blackhole bh) throws JsonProcessingException {
// final HashMap<String, Object> map = mapper.readValue(glossaryEvent, mapTypeRef);
// if (map.get("subject").equals("glossaryFeed")) {
// final String id = (String) map.get("id");
// final String type = (String) map.get("type");
// final String description = (String) map.get("description");
// final String data = mapper.writeValueAsString(map.get("data"));
// bh.consume(new Object[]{id, type, data, description});
// }
// }
//
// @Benchmark
// public void cloudEventJParse(Blackhole bh) throws JsonProcessingException {
// final ObjectNode objectNode = fastParser.parse(glossaryEvent).asObject();
// if (objectNode.getNode("subject").equalsContent("glossaryFeed")) {
// final String id = objectNode.getStringNode("id").toUnencodedString();
// final String type = objectNode.getStringNode("type").toUnencodedString();
// final String description = objectNode.getStringNode("description").toUnencodedString();
// final String data = Json.serializeToString(objectNode.getNode("data"));
// bh.consume(new Object[]{id, type, data, description});
// }
// }
//
@Benchmark
public void jParseFastFloatArray(Blackhole bh) {
bh.consume(this.fastParser.parse(doublesJsonData).asArray().getFloatArray());
}The method jParseFastFloatArray is a benchmark method defined in the class io.nats.jparse.BenchMark. It is used to compare the performance of parsing a JSON array of floating-point numbers using a specific parser called fastParser.
Here is a step-by-step description of what the method is doing:
-
It takes a parameter
bhof typeBlackhole. This is an object provided by the benchmark framework that can be used to consume the result of the benchmark, preventing the compiler from optimizing away the benchmarked code. -
The method executes the following code:
bh.consume(this.fastParser.parse(doublesJsonData).asArray().getFloatArray());a. The `fastParser` parses the `doublesJsonData`, which is a JSON array of floating-point numbers.
b. The parsed result is treated as an array using the `asArray()` method.
c. The `getFloatArray()` method is called on the parsed array to get an array of floating-point numbers.
d. The result of `getFloatArray()` is consumed by the `Blackhole` object, ensuring that the benchmarked code is not optimized away.
- The method does not return any value.
Overall, the jParseFastFloatArray method benchmarks the parsing performance of the fastParser for a JSON array of floating-point numbers and consumes the result using the Blackhole object.


The CharArrayOffsetCharSource class is a concrete implementation of the CharSource abstract class and the ParseConstants interface. It represents a character source backed by a character array, where the starting position of the character sequence is indicated by an offset. This class provides methods for parsing integer, long, float, and double values from the character sequence. It also includes a validation method to check if a substring represents a valid integer. Additionally, it implements an errorDetails method that generates a detailed error message based on the current character being processed and the current parsing state.
public static String debugCharDescription(int c) {
String charString;
if (c == ' ') {
charString = "[SPACE]";
} else if (c == '\t') {
charString = "[TAB]";
} else if (c == '\n') {
charString = "[NEWLINE]";
} else if (c == ETX) {
charString = "ETX";
} else {
charString = "'" + (char) c + "'";
}
charString = charString + " with an int value of " + c;
return charString;
}The debugCharDescription method in the CharArrayOffsetCharSource class is responsible for providing a textual description of a given character based on its ASCII value.
Here is the step-by-step description of what this method does:
- The method takes an integer value
cas input. - It initializes a variable called
charStringto hold the description of the character. - It checks if the input character
cis equal to a space character. If true, it setscharStringto the string "[SPACE]". - If the input character
cis a tab character, it setscharStringto the string "[TAB]". - If the input character
cis a newline character, it setscharStringto the string "[NEWLINE]". - If
cis equal to a special character identified asETX, it setscharStringto the string "ETX". - If the character
cdoes not match any of the above conditions, it appends the character tocharStringby converting the ASCII value ofcto a character using(char) c. For example, ifcis 65, the character 'A' will be appended as "'A'". - Finally, the method appends " with an int value of " and the value of
cto the current value ofcharString. - The method returns the final value of
charString, which represents the description of the character based on its ASCII value.
public int next()
@Override
public int next() {
if (index + 1 >= sourceEndIndex) {
index = sourceEndIndex;
return ETX;
}
return data[++index];
}This method is overridden from the parent class to provide the functionality of iterating over the characters in the underlying char array source.
- Check if the current index (
index) incremented by 1 is greater than or equal to the end index of the source array (sourceEndIndex).- If true, set
indextosourceEndIndexand return theETXconstant, which indicates the end of the stream.
- If true, set
- Otherwise, increment
indexby 1 and return the character at the updated index in thedataarray.
Note: The data array is the char array source, and index is a variable that keeps track of the current position in the array. The ETX constant represents the end of the stream.

public int findAttributeEnd()
@Override
public int findAttributeEnd() {
int index = this.index;
final char[] data = this.data;
final int end = this.sourceEndIndex;
loop: for (; index < end; index++) {
char ch = data[index];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
this.index = index;
break loop;
}
}
return index;
}The findAttributeEnd method is defined in the CharArrayOffsetCharSource class and is used to find the end index of an attribute. Here is a step-by-step description of how the method works:
-
The method overrides the
findAttributeEndmethod defined in the parent class. -
It initializes the local variable
indexwith the value of the instance variablethis.index. This variable represents the current index position in the character array. -
It creates a local variable
dataand assigns it the value of the instance variablethis.data. This variable represents the character array from which the attribute is being extracted. -
It creates a local variable
endand assigns it the value of the instance variablethis.sourceEndIndex. This variable represents the end index of the character array. -
It enters a loop that iterates from the current index position (
index) to the end index (end) of the character array. -
Within each iteration of the loop, it retrieves the character at the current index position (
index) from the character array and assigns it to the variablech. -
It checks the value of
chusing a switch statement. -
If
chmatches any of the case valuesNEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS, orATTRIBUTE_SEP, it updates the instance variablethis.indexwith the value ofindexand breaks out of the loop labeledloop. -
After the loop ends, it returns the value of index, which represents the end index of the attribute.
In summary, the findAttributeEnd method iterates through a character array starting from the current index position and looks for specific characters that indicate the end of an attribute. Once a matching character is found, it updates the instance variable this.index and returns the end index.

public boolean findChar(char c)
@Override
public boolean findChar(char c) {
int index = this.index;
final char[] data = this.data;
final int end = sourceEndIndex;
for (; index < end; index++) {
if (data[index] == c) {
this.index = index;
return true;
}
}
return false;
}The findChar method is used to search for a specific character within a character array. Here is a step-by-step description of what the method does:
- The method receives a character
cas a parameter. - It assigns the current index of the CharArrayOffsetCharSource object to the local variable
index. - It retrieves the character array
datafrom the CharArrayOffsetCharSource object. - It retrieves the end index of the source from the CharArrayOffsetCharSource object and assigns it to the local variable
end. - It starts a loop that iterates from the current index
indexuntil the end indexend. - Within each iteration, it checks if the character at position
indexwithin thedataarray is equal to the characterc. - If a match is found, it updates the current index of the CharArrayOffsetCharSource object to the value of
indexand returnstrue. - If no match is found after iterating through the entire array, it simply returns
false. - The method is marked as
@Override, indicating that it overrides a method from a superclass or interface.
Overall, the findChar method performs a linear search for a specific character c within the character array data. It updates the current index of the CharArrayOffsetCharSource object if a match is found and returns true. Otherwise, it returns false indicating that the character was not found.

public void checkForJunk()
@Override
public void checkForJunk() {
int index = this.index;
final char[] data = this.data;
final int end = this.sourceEndIndex;
int ch = ETX;
for (; index < end; index++) {
ch = data[index];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
continue;
default:
throw new UnexpectedCharacterException("Junk", "Unexpected extra characters", this);
}
}
}The checkForJunk method, defined in the io.nats.jparse.source.CharArrayOffsetCharSource class, is used to check for any junk characters in the provided character array.
Here is a step-by-step description of what the method does:
-
It starts by initializing variables:
indexwith the current index position in the character array,datawith the provided character array,endwith the end index of the character array, andchwith the ASCII value of ETX (End-of-Text). -
It enters a for loop that iterates from the current
indexto theendindex of the character array. -
Inside the loop, it assigns the value of
data[index]toch, which represents the current character being checked. -
It uses a switch statement to check the value of
chagainst predefined cases. The cases being checked are:a)
NEW_LINE_WS: Represents a new line whitespace character. b)CARRIAGE_RETURN_WS: Represents a carriage return whitespace character. c)TAB_WS: Represents a tab whitespace character. d)SPACE_WS: Represents a space whitespace character.If
chmatches any of the above cases, the loop continues to the next iteration without executing any further code. This means that if the current character is a whitespace character, it is considered valid and not classified as junk. -
If the value of
chdoes not match any of the cases above, it means that an unexpected character (considered as junk) has been encountered in the character array. In this case, anUnexpectedCharacterExceptionis thrown with the message "Junk" and "Unexpected extra characters". Thethisreference, representing the current instance of theCharArrayOffsetCharSourceclass, is passed as an argument to the exception. -
The for loop continues to the next iteration, and steps 3-5 are repeated until all characters in the character array have been checked.
By the end of the method, if no UnexpectedCharacterException is thrown, it means that there are no junk characters found in the provided character array.

public int nextSkipWhiteSpace()
@Override
public int nextSkipWhiteSpace() {
int index = this.index + 1;
final char[] data = this.data;
final int endIndex = sourceEndIndex;
int ch = ETX;
loop: for (; index < endIndex; index++) {
ch = data[index];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
continue;
default:
break loop;
}
}
this.index = index;
return index == endIndex ? ETX : ch;
}The nextSkipWhiteSpace method is defined in the CharArrayOffsetCharSource class in the io.nats.jparse.source package.
This method is used to skip white space characters in the data array starting from the current index. It returns the index of the next non-white space character, or ETX (end of text) if there are no more characters.
Here is a step-by-step description of what the method does:
- Increment
indexby 1 to start from the next character. - Store the reference to the
dataarray in a local variable nameddata. - Store the value of
sourceEndIndexin a local variable namedendIndex. - Create a variable
chand initialize it with theETXvalue. - Start a loop that will iterate from the current
indexuntil theendIndex. - Inside the loop, assign the character at
data[index]toch. - Use a switch statement to check the value of
ch.- If
chis equal toNEW_LINE_WSorCARRIAGE_RETURN_WSorTAB_WSorSPACE_WS, continue to the next iteration of the loop. - Otherwise, break out of the loop.
- If
- Update the
indexwith the value ofindex. - Return
ETXif theindexis equal toendIndex, otherwise return the value ofch.
This method effectively skips any white space characters (including new lines, carriage returns, tabs, and spaces) in the data array until a non-white space character is encountered. It then returns the index of that non-white space character. If there are no more characters after skipping white space, it returns the ETX value.

public char skipWhiteSpace()
@Override
public char skipWhiteSpace() {
int index = this.index;
final char[] data = this.data;
final int endIndex = sourceEndIndex;
char ch;
loop: for (; index < endIndex; index++) {
ch = data[index];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
continue;
default:
break loop;
}
}
this.index = index;
return data[index];
}The skipWhiteSpace method in the CharArrayOffsetCharSource class is used to skip any white space characters (spaces, tabs, new lines, and carriage returns) in the character array.
Here is a step-by-step description of what the method is doing:
- It first initializes a local variable
indexwith the current value ofthis.index, which represents the current position in the character array. - It also initializes a local variable
datawith the reference to the character arraythis.datathat contains the source data. - It gets the
endIndexfrom thesourceEndIndexinstance variable, which represents the end position in the character array. - It declares a variable
chto store the current character being examined. - It enters a loop that iterates over the character array starting from the current
indextill theendIndex. - Inside the loop, it checks the character at the current index
data[index]against a set of white space characters:NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS, andSPACE_WS. - If the character matches any of the white space characters, the loop continues to the next iteration without performing any action.
- If the character does not match any of the white space characters, it breaks out of the loop using the
break loop;statement. - After the loop completes, it updates the
indexinstance variable with the currentindexvalue, representing the new position after skipping white space. - Finally, it returns the character at that position
data[index]from the character array.
So, the skipWhiteSpace method essentially advances the position in the character array to the next non-white space character and returns that character.

public String toEncodedStringIfNeeded(int startIndex, int endIndex)
@Override
public String toEncodedStringIfNeeded(int startIndex, int endIndex) {
final int start = startIndex + sourceStartIndex;
final int end = endIndex + sourceStartIndex;
if (CharArrayUtils.hasEscapeChar(data, start, end)) {
return getEncodedString(startIndex, endIndex);
} else {
return this.getString(startIndex, endIndex);
}
}The toEncodedStringIfNeeded method in the io.nats.jparse.source.CharArrayOffsetCharSource class is used to convert a portion of a character array into a string representation if it contains escape characters.
Here is a step-by-step description of what the method does:
-
The method overrides the
toEncodedStringIfNeededmethod from the ancestor class. -
The method takes two parameters -
startIndexandendIndex, which denote the range of characters to be converted to a string. -
It calculates the actual start index and end index within the
datacharacter array by adding thestartIndexandendIndexto thesourceStartIndexinstance variable. -
It checks if the portion of the character array from the calculated start index to end index (inclusive) contains any escape characters using the
CharArrayUtils.hasEscapeCharmethod. -
If the portion contains escape characters, it calls the
getEncodedStringmethod with thestartIndexandendIndexparameters to obtain the encoded string representation. -
If the portion does not contain any escape characters, it calls the
getStringmethod with thestartIndexandendIndexparameters to obtain the regular string representation. -
Finally, it returns the obtained string representation either with escape characters encoded or without any encoding based on the presence of escape characters within the portion of the character array specified by the
startIndexandendIndex.
public NumberParseResult findEndOfNumberFast()
@Override
public NumberParseResult findEndOfNumberFast() {
int i = index + 1;
char ch = 0;
final char[] data = this.data;
final int endIndex = this.sourceEndIndex;
for (; i < endIndex; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i - sourceStartIndex, false);
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
case DECIMAL_POINT:
index = i;
return findEndOfFloatFast();
case EXPONENT_MARKER:
case EXPONENT_MARKER2:
index = i;
return parseFloatWithExponentFast();
default:
throw new IllegalStateException("Unexpected character " + ch + " at index " + index);
}
}
index = i;
return new NumberParseResult(i - sourceStartIndex, false);
}The method findEndOfNumberFast in the class io.nats.jparse.source.CharArrayOffsetCharSource is used to find the end position of a number within a character array.
Here is a step-by-step breakdown of what this method does:
-
It initializes the local variable
ito the value ofindex + 1. -
It initializes the local variable
chto 0. -
It assigns the value of
data(a char array) to the local variabledata. -
It assigns the value of
sourceEndIndex(the end index of the source) to the local variableendIndex. -
It starts a loop from
iuntil it reachesendIndex. -
Inside the loop, it retrieves the character at index
ifrom thedataarray and assigns it toch. -
It uses a switch statement to handle different cases based on the value of
ch.-
If
chmatches any of the specified cases (NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, SPACE_WS, ATTRIBUTE_SEP, ARRAY_SEP, OBJECT_END_TOKEN, ARRAY_END_TOKEN), it updates the value ofindextoiand returns a newNumberParseResultobject with the length of the number (i - sourceStartIndex) and a boolean indicating that the number does not have a decimal point or exponent. -
If
chmatches any digit character (NUM_0, NUM_1, NUM_2, ..., NUM_9), it continues to the next iteration of the loop. -
If
chmatches the decimal point character (DECIMAL_POINT), it updates the value ofindextoiand calls thefindEndOfFloatFastmethod to find the end of a floating-point number. -
If
chmatches the exponent marker characters (EXPONENT_MARKER, EXPONENT_MARKER2), it updates the value ofindextoiand calls theparseFloatWithExponentFastmethod to parse the number with exponent notation. -
If none of the above cases match, it throws an
IllegalStateExceptionwith an error message indicating the unexpected character and its index.
-
-
After the loop ends, it updates the value of
indextoi. -
It returns a new
NumberParseResultobject with the length of the number (i - sourceStartIndex) and a boolean indicating that the number does not have a decimal point or exponent.
private NumberParseResult findEndOfFloatFast() {
int i = index + 1;
char ch = 0;
final char[] data = this.data;
final int endIndex = this.sourceEndIndex;
for (; i < endIndex; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i - sourceStartIndex, true);
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
case EXPONENT_MARKER:
case EXPONENT_MARKER2:
index = i;
return parseFloatWithExponentFast();
default:
throw new UnexpectedCharacterException("Parsing JSON Float Number", "Unexpected character", this, ch, i);
}
}
index = i;
return new NumberParseResult(i - sourceStartIndex, true);
}The findEndOfFloatFast method in the io.nats.jparse.source.CharArrayOffsetCharSource class is responsible for finding the end of a float number in a JSON source.
Here is a step-by-step description of what the method does:
- Initialize the variable
iwith the value ofindex + 1. This indicates the starting index of the float number. - Initialize the variable
chwith the value0. - Get a reference to the
dataarray and store it in a local variable. - Get the
endIndexof the source and store it in a local variable. - Start a loop from
itoendIndex. - Get the character at index
ifrom thedataarray and store it in the variablech. - Switch on the value of
chto perform different actions based on its type.- If
chis a white space character (e.g.,NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS), comma (ATTRIBUTE_SEP), curly brace (OBJECT_END_TOKEN), or square bracket (ARRAY_END_TOKEN), set theindextoiand return aNumberParseResultobject indicating the number of characters parsed and that parsing is successful. - If
chis a digit character (NUM_0,NUM_1,NUM_2, ...,NUM_9), continue with the loop to parse the next character. - If
chis an exponent marker character (EXPONENT_MARKER,EXPONENT_MARKER2), set theindextoiand call theparseFloatWithExponentFast()method to parse the number with exponent notation. - If
chis any other character, throw anUnexpectedCharacterExceptionindicating that an unexpected character is encountered while parsing a JSON float number.
- If
- After the loop completes, set the
indextoito indicate the end index of the float number. - Return a
NumberParseResultobject indicating the number of characters parsed and a flag indicating a successful parse.
Note: The specific values (e.g., NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, etc.) mentioned in the switch cases are assumed to be constants defined elsewhere in the code.

private NumberParseResult parseFloatWithExponentFast() {
int i = index + 1;
char ch = 0;
int signOperator = 0;
final char[] data = this.data;
final int end = sourceEndIndex;
for (; i < end; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i - sourceStartIndex, true);
case MINUS:
case PLUS:
signOperator++;
if (signOperator > 1) {
throw new IllegalStateException("Too many sign operators when parsing exponent of float");
}
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
default:
throw new IllegalStateException("Unexpected character " + ch + " at index " + index);
}
}
index = i;
return new NumberParseResult(i - sourceStartIndex, true);
}This method is defined in the io.nats.jparse.source.CharArrayOffsetCharSource class.
- Initialize a variable
iwith the value ofindex + 1. - Initialize a variable
chwith a value of 0. - Initialize a variable
signOperatorwith a value of 0. - Get the character array
datafrom the instance ofCharArrayOffsetCharSource. - Get the end index
endof the character source. - Enter a loop starting from
iuntilend. - Get the character at index
ifrom thedataarray and assign it toch. - Enter a switch statement based on the value of
ch:- If
chmatches any of the following cases:-
NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS,ATTRIBUTE_SEP,ARRAY_SEP,OBJECT_END_TOKEN, orARRAY_END_TOKEN, - Update the
indexvariable toiand return a newNumberParseResultobject with the differencei - sourceStartIndexand a value oftrue.
-
- If
chmatches eitherMINUSorPLUS,- Increment the
signOperatorvariable by 1. - If
signOperatoris greater than 1, throw anIllegalStateExceptionwith the message "Too many sign operators when parsing exponent of float".
- Increment the
- If
chmatches any of the following cases:-
NUM_0,NUM_1,NUM_2,NUM_3,NUM_4,NUM_5,NUM_6,NUM_7,NUM_8, orNUM_9, - Continue to the next iteration of the loop.
-
- If
chdoes not match any of the above cases, throw anIllegalStateExceptionwith the message "Unexpected characterchat indexindex".
- If
- After the loop, update the
indexvariable toi. - Return a new
NumberParseResultobject with the differencei - sourceStartIndexand a value oftrue.
public int findEndOfEncodedStringFast()
@Override
public int findEndOfEncodedStringFast() {
int i = ++index;
final char[] data = this.data;
final int end = sourceEndIndex;
boolean controlChar = false;
for (; i < end; i++) {
char ch = data[i];
switch(ch) {
case CONTROL_ESCAPE_TOKEN:
controlChar = !controlChar;
continue;
case STRING_END_TOKEN:
if (!controlChar) {
index = i + 1;
return i;
}
controlChar = false;
break;
default:
controlChar = false;
break;
}
}
throw new IllegalStateException("Unable to find closing for String");
}The findEndOfEncodedStringFast() method, defined in the io.nats.jparse.source.CharArrayOffsetCharSource class, is used to find the closing position of an encoded string within a character array.
Here is a step-by-step description of how the method works:
-
The method starts by incrementing the
indexvariable by 1 and assigning its value toi. -
It then retrieves the character array (
data) and the end index (end) from the source. -
The method initializes a boolean variable
controlCharto false. This variable keeps track of whether a control character (such as an escape character) has been encountered. -
A for loop is initiated, iterating through each character in the character array, starting from index
iand going up toend. -
Within the loop, the current character (
ch) is retrieved. -
A switch statement is used to check the value of the current character:
a. If the character is equal to
CONTROL_ESCAPE_TOKEN, thecontrolCharvariable is toggled (flipped) by assigning it the opposite value (true becomes false, false becomes true), and the loop continues to the next iteration.b. If the character is equal to
STRING_END_TOKEN, andcontrolCharis false (indicating that it's not within a control sequence), then the method updates theindexvariable to be equal toi + 1, and returns the current value ofi. This signifies that the closing position of the encoded string has been found.c. If the character does not match either of the above cases, the
controlCharvariable is set to false, indicating that it is not within a control sequence. -
If none of the characters within the loop match the conditions to find the closing position of the encoded string, the method throws an
IllegalStateExceptionwith a message stating "Unable to find closing for String". This serves as an indication that the closing position could not be found.
In summary, the findEndOfEncodedStringFast() method iterates through a character array, checking each character to determine the closing position of an encoded string. It considers control characters and checks for the end token to determine when the closing position is reached.

private int findEndOfStringControlEncode(int i) {
final char[] data = this.data;
final int length = data.length;
char ch = 0;
ch = data[i];
switch(ch) {
case CONTROL_ESCAPE_TOKEN:
case STRING_END_TOKEN:
case 'n':
case 'b':
case '/':
case 'r':
case 't':
case 'f':
return i;
case 'u':
return findEndOfHexEncoding(i);
default:
throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
}
}The findEndOfStringControlEncode method is defined in the io.nats.jparse.source.CharArrayOffsetCharSource class and takes an integer i as input. Below is a step-by-step description of what the method is doing:
- The method begins by declaring a local variable
data, which is assigned the value ofthis.data.this.datarefers to a char array that represents the source data being processed. - A local variable
lengthis declared and assigned the length of thedataarray. - A local variable
chof typecharis declared and initialized to 0. - The character at index
iof thedataarray is assigned toch. - A
switchstatement is used to perform different actions based on the value ofch.- If
chis equal toCONTROL_ESCAPE_TOKEN,STRING_END_TOKEN,'n','b','/','r','t', or'f', the method simply returnsi. These characters represent the control escape token and various escape sequences commonly found in JSON strings. - If
chis equal to'u', the method calls thefindEndOfHexEncodingmethod withias an argument and returns the result. This suggests thatfindEndOfHexEncodingis responsible for finding the end of a hexadecimal encoding, which is likely used to decode Unicode characters in the JSON string. - If none of the above cases match, it means that an unexpected character was encountered while trying to find the closing for a string. In this case, an
UnexpectedCharacterExceptionis thrown with a descriptive error message, including the current source (this), the unexpected characterch, and the current indexi.
- If
That concludes the step-by-step description of the findEndOfStringControlEncode method.

public int findEndOfEncodedString()
@Override
public int findEndOfEncodedString() {
int i = ++index;
final char[] data = this.data;
final int length = data.length;
char ch = 0;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case CONTROL_ESCAPE_TOKEN:
i = findEndOfStringControlEncode(i + 1);
continue;
case STRING_END_TOKEN:
index = i + 1;
return i;
default:
if (ch >= SPACE_WS) {
continue;
}
throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
}
}
throw new UnexpectedCharacterException("Parsing JSON Encoded String", "Unable to find closing for String", this, ch, i);
}The findEndOfEncodedString method is defined in the CharArrayOffsetCharSource class in the io.nats.jparse.source package. Here is a step-by-step description of what this method does:
- Declare a local variable
iand initialize it with the value of++index. This increments the value of theindexvariable by 1 and assigns the updated value toi. - Retrieve the
dataarray fromthisobject. This is the character array that the method operates on. - Get the length of the
dataarray and store it in thelengthvariable. - Declare a variable
chand initialize it with 0. - Start a loop that iterates through the array from the current value of
ito the end of the array (length). - Get the character at the current index
ifrom thedataarray and assign it toch. - Use a switch statement to perform different actions based on the value of
ch:- If
chis equal to theCONTROL_ESCAPE_TOKENconstant, call thefindEndOfStringControlEncodemethod with the argumenti + 1and assign its return value toi. This method is not provided, so we can't describe its exact behavior. - If
chis equal to theSTRING_END_TOKENconstant, update the value of theindexvariable toi + 1and return the current value ofi. - If none of the above conditions are true, check if
chis greater than or equal to theSPACE_WSconstant. If it is, continue to the next iteration of the loop. - If none of the conditions above are true, throw an
UnexpectedCharacterExceptionwith a message indicating that an unexpected character was encountered while finding the closing of a string. The exception includes information about the currentCharSource, the unexpected characterch, and its positioni.
- If
- If the loop completes without finding the closing of the string, throw an
UnexpectedCharacterExceptionwith a message indicating that the closing for the string could not be found. The exception includes information about the currentCharSource, the last characterchencountered, and its positioni.
private int findEndOfHexEncoding(int index) {
final char[] data = this.data;
final int length = data.length;
if (isHex(data[++index]) && isHex(data[++index]) && isHex(data[++index]) && isHex(data[++index])) {
return index;
} else {
throw new UnexpectedCharacterException("Parsing hex encoding in a string", "Unexpected character", this);
}
}The method findEndOfHexEncoding is defined in the class io.nats.jparse.source.CharArrayOffsetCharSource. It takes an index as a parameter and returns an integer.
Here is a step-by-step description of what the method does:
-
The method starts by getting the
dataarray and its length from the current instance ofCharArrayOffsetCharSource. -
It then checks if the character at the next index in the
dataarray is a valid hexadecimal character (isHex). It does this repeatedly for the next 4 characters by incrementing theindexfor each check. -
If all 4 characters are valid hexadecimal characters, the method returns the current value of
index. -
If any of the characters are not valid hexadecimal characters, the method throws an
UnexpectedCharacterException. The exception message states that it occurred while parsing a hex encoding in a string, and the unexpected character is included in the message. Thethisreference is passed as an argument to provide additional context.
In summary, the findEndOfHexEncoding method scans the data array starting from the given index and checks if the next 4 characters form a valid hex encoding. If they do, it returns the index. If not, it throws an exception.

private boolean isHex(char datum) {
switch(datum) {
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return true;
default:
return false;
}
}The isHex method in the io.nats.jparse.source.CharArrayOffsetCharSource class is used to determine whether a given character is a hexadecimal digit. Here is a step-by-step description of what the method does:
-
The method takes a single parameter
datum, which represents the character to be tested. -
The method uses a
switchstatement to check the value of thedatumcharacter. -
If the
datumcharacter is any of the following characters: 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', or '9', then the method returnstrue. These characters represent valid hexadecimal digits. -
If the
datumcharacter is not one of the specified hexadecimal digits, thedefaultcase is executed, and the method returnsfalse. -
So overall, the
isHexmethod determines whether a character is a hexadecimal digit by checking if it falls within the specified range of valid hexadecimal characters. If the character is within the range, the method returnstrue; otherwise, it returnsfalse.
public int findEndString()
@Override
public int findEndString() {
int i = ++index;
final char[] data = this.data;
final int length = data.length;
char ch = 0;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case STRING_END_TOKEN:
index = i;
return i;
default:
if (ch >= SPACE_WS) {
continue;
}
throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
}
}
throw new UnexpectedCharacterException("Parsing JSON String", "Unable to find closing for String", this, ch, i);
}This findEndString method is defined in the CharArrayOffsetCharSource class and it overrides the same method from the superclass.
Here is a step-by-step description of what this method does:
- It starts by incrementing the
indexvariable. - It retrieves the
dataarray and its length from the class instance. - It declares a
chvariable and sets it to 0. - It enters a loop from the incremented
indexup to the length of thedataarray. - Inside the loop, it assigns the current character of the
dataarray toch. - It checks for a switch case where
chis equal to theSTRING_END_TOKEN.- If so, it updates the
indexvariable to the current index and returns the index. - If not, it continues to the next step.
- If so, it updates the
- It then checks if
chis greater than or equal toSPACE_WS. If true, it continues to the next iteration of the loop. - If the character doesn't match the switch case and is not greater than
SPACE_WS, it throws anUnexpectedCharacterExceptionwith the appropriate message, passing in this object,ch, and the current index. - If the loop completes without finding a match, it throws an
UnexpectedCharacterExceptionwith the appropriate message, passing in this object,ch, and the current index.
Note: The specific values for STRING_END_TOKEN and SPACE_WS are not included in the code snippet provided and may be defined elsewhere in the codebase or imported from another class or module.

public NumberParseResult findEndOfNumber()
@Override
public NumberParseResult findEndOfNumber() {
final char startCh = getCurrentChar();
final int startIndex = index;
char ch = startCh;
int i = index + 1;
final char[] data = this.data;
final int endIndex = this.sourceEndIndex;
loop: for (; i < endIndex; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
break loop;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
case DECIMAL_POINT:
if (startCh == MINUS) {
final int numLenSoFar = i - startIndex;
if (numLenSoFar == 1) {
throw new UnexpectedCharacterException("Parsing JSON Number", "Unexpected character", this, ch, i);
}
}
index = i;
return findEndOfFloat();
case EXPONENT_MARKER:
case EXPONENT_MARKER2:
index = i;
return parseFloatWithExponent();
default:
throw new UnexpectedCharacterException("Parsing JSON Number", "Unexpected character", this, ch, i);
}
}
index = i;
final int numLength = i - startIndex;
switch(startCh) {
case NUM_0:
if (numLength != 1) {
throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't start with a 0 ", this, startCh, startIndex);
}
break;
case PLUS:
throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't start with a plus ", this, startCh, startIndex);
case MINUS:
switch(numLength) {
case 1:
throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't be only a minus, number is missing", this, startCh, startIndex);
case 2:
break;
default:
if (data[startIndex + 1] == NUM_0) {
throw new UnexpectedCharacterException("Parsing JSON Int Number", "0 can't be after minus sign", this, startCh, startIndex);
}
}
}
return new NumberParseResult(i - this.sourceStartIndex, false);
}The method findEndOfNumber in the class io.nats.jparse.source.CharArrayOffsetCharSource is responsible for finding the end of a number while parsing JSON data. Here is the step-by-step description of what this method does based on its code:
- It retrieves the current character from the source and assigns it to the variable
startCh. - It sets the starting index to the current index.
- It initializes the variable
chwith the value ofstartChand increments the variableiby 1. - It retrieves the character array
dataand the end indexendIndexfrom the source. - It enters a loop that iterates over the characters from
itoendIndex. - For each character
chin the loop:- If the character is one of the following:
NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS,ATTRIBUTE_SEP,ARRAY_SEP,OBJECT_END_TOKEN, orARRAY_END_TOKEN, the loop breaks. - If the character is one of the digits
NUM_0toNUM_9, the loop continues. - If the character is a
DECIMAL_POINTand thestartChisMINUS, it checks if the length of the number is 1. If it is, it throws an exception. Then, it sets the current index toiand returns the result of calling thefindEndOfFloatmethod. - If the character is an
EXPONENT_MARKERor anEXPONENT_MARKER2, it sets the current index toiand returns the result of calling theparseFloatWithExponentmethod. - If none of the above conditions match, it throws an exception.
- If the character is one of the following:
- It sets the current index to
i. - It calculates the length of the number by subtracting the starting index from
iand assigns it tonumLength. - It checks the value of the
startChcharacter:- If it is
NUM_0, it checks ifnumLengthis not equal to 1. If it is not, it throws an exception. - If it is
PLUS, it throws an exception. - If it is
MINUS, it checks the value ofnumLength:- If it is 1, it throws an exception.
- If it is 2, it continues.
- If it is greater than 2 and the character following the
MINUSisNUM_0, it throws an exception.
- If it is
- It creates a new
NumberParseResultobject with the length of the number (i -this.sourceStartIndex) and the valuefalse. - It returns the
NumberParseResultobject.
private NumberParseResult findEndOfFloat() {
int i = index + 1;
char ch = (char) next();
if (!isNumber(ch)) {
throw new UnexpectedCharacterException("Parsing float part of number", "After decimal point expecting number but got", this, ch, this.index);
}
final char[] data = this.data;
final int endIndex = this.sourceEndIndex;
for (; i < endIndex; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i - sourceStartIndex, true);
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
case EXPONENT_MARKER:
case EXPONENT_MARKER2:
index = i;
return parseFloatWithExponent();
default:
throw new UnexpectedCharacterException("Parsing JSON Float Number", "Unexpected character", this, ch, i);
}
}
index = i;
return new NumberParseResult(i - sourceStartIndex, true);
}The method findEndOfFloat in the CharArrayOffsetCharSource class is used to find the end of a floating-point number in a JSON input string. Here is a step-by-step description of what the method does:
-
The method initializes a local variable
ito the value ofindex + 1and retrieves the next characterchfrom the input stream using thenext()method. -
It checks if the character
chis not a valid number character. If it's not, it throws anUnexpectedCharacterException, indicating that a number was expected after the decimal point but a different character was encountered. -
The method then retrieves the underlying character array
dataand the end index of the source string. -
It enters a loop that iterates from
itoendIndex. -
Inside the loop, the method checks the current character
chagainst a series of predefined characters that can signal the end of a floating-point number. These characters include whitespace characters (NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS), attribute and array separators (ATTRIBUTE_SEP,ARRAY_SEP), and object and array end tokens (OBJECT_END_TOKEN,ARRAY_END_TOKEN). If a match is found, the method updates theindexvariable to the current value ofiand returns a newNumberParseResultobject containing the length of the parsed number asi - sourceStartIndexand a flag indicating that the number is complete (true). -
If the current character
chis not one of the predefined end tokens, the method checks if it's a digit (NUM_0toNUM_9). If it is, the loop continues to the next iteration. This allows the method to handle numbers with digits after the decimal point. -
If the current character
chis an exponent marker (EXPONENT_MARKERorEXPONENT_MARKER2), the method updates theindexvariable to the current value ofiand returns the result of calling theparseFloatWithExponent()method. This method handles parsing floating-point numbers with exponent notation. -
If none of the above conditions are met, the method throws an
UnexpectedCharacterException, indicating that an unexpected character was encountered while parsing the JSON float number. -
After the loop completes without finding an end token, the method updates the
indexvariable to the current value ofiand returns a newNumberParseResultobject containing the length of the parsed number asi - sourceStartIndexand a flag indicating that the number is complete (true).
private boolean isNumber(final char ch) {
switch(ch) {
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
return true;
default:
return false;
}
}The isNumber method in the CharArrayOffsetCharSource class is used to determine whether a given character is a number. Here is a step-by-step description of how the method works:
-
The method takes a
charparameter calledch. -
It uses a switch statement to check the value of the
chcharacter. -
The
casestatements in the switch statement represent the numbers0to9. -
If the value of
chmatches any of the cases (i.e., it is a number), the method returnstrue. -
If the value of
chdoes not match any of the cases (i.e., it is not a number), the method returnsfalse.
That's the step-by-step description of how the isNumber method in the CharArrayOffsetCharSource class works.

private NumberParseResult parseFloatWithExponent() {
char ch = (char) next();
if (!isNumberOrSign(ch)) {
throw new UnexpectedCharacterException("Parsing exponent part of float", "After exponent expecting number or sign but got", this, ch, this.index);
}
if (isSign(ch)) {
ch = (char) next();
if (!isNumber(ch)) {
throw new UnexpectedCharacterException("Parsing exponent part of float after sign", "After sign expecting number but got", this, ch, this.index);
}
}
int i = index + 1;
final char[] data = this.data;
final int endIndex = this.sourceEndIndex;
for (; i < endIndex; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i - sourceStartIndex, true);
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
default:
throw new UnexpectedCharacterException("Parsing Float with exponent", "Unable to find closing for Number", this, ch, i);
}
}
index = i;
return new NumberParseResult(i - sourceStartIndex, true);
}The method parseFloatWithExponent in the CharArrayOffsetCharSource class is used to parse a floating-point number with an exponent. Below is a step-by-step description of what the method does:
- The method starts by fetching the next character from the input stream and assigns it to the variable
ch. - It checks if the character
chis a valid number or sign character using theisNumberOrSignmethod. If it is not, it throws anUnexpectedCharacterExceptionwith an appropriate error message. - If the character
chis a sign character, it fetches the next character and assigns it toch. If the next character is not a number, it throws anUnexpectedCharacterExceptionwith an appropriate error message. - It initializes a variable
iwith the value ofindex + 1, which represents the next index to start parsing at. - It assigns the internal character array
datafrom theCharArrayOffsetCharSourceinstance to a local variabledata. - It assigns the value of
sourceEndIndexto a local variableendIndex, which represents the end index of the source. - It enters a
forloop that iterates fromitoendIndex. - Inside the loop, it assigns the character at index
iin thedataarray toch. - It checks if
chis one of the following characters:NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS,ATTRIBUTE_SEP,ARRAY_SEP,OBJECT_END_TOKEN, orARRAY_END_TOKEN. If it is, it updates theindexvariable toiand returns a newNumberParseResultobject with the length of the parsed number (i - sourceStartIndex) andtrueindicating success. - If
chis one of the digit charactersNUM_0toNUM_9, it continues the loop iteration without any special action. - If
chdoes not match any of the above cases, it throws anUnexpectedCharacterExceptionwith an appropriate error message. - After the loop exits, it updates the
indexvariable toiand returns a newNumberParseResultobject with the length of the parsed number (i - sourceStartIndex) andtrueindicating success.
Overall, the method iterates through the characters starting from the initial index and checks if each character is a valid part of the exponent part of a floating-point number. It stops parsing when it encounters a character that is not part of the exponent or reaches the end of the input.

private boolean isNumberOrSign(char ch) {
switch(ch) {
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
return true;
default:
return false;
}
}The isNumberOrSign method is defined in the io.nats.jparse.source.CharArrayOffsetCharSource class. It is a private method that takes a single character as input and returns a boolean value.
The purpose of this method is to determine whether a given character is a number or a mathematical sign (either a minus or plus symbol).
The method contains a switch-case statement that checks the input character against several predefined constants representing the digits 0-9, as well as the minus and plus signs.
- If the input character matches any of these constants, the method will return
true, indicating that the character is a number or a sign. - If the input character does not match any of the constants, the method will return
false, indicating that the character is not a number or a sign.
Here is the step-by-step description of the isNumberOrSign method based on its body:
-
Declare a private boolean method named
isNumberOrSignthat takes a single characterchas input. -
Start a switch-case statement to check the value of
ch. -
In each case, compare the value of
chto the following constants:-
NUM_0, representing the character '0' -
NUM_1, representing the character '1' -
NUM_2, representing the character '2' -
NUM_3, representing the character '3' -
NUM_4, representing the character '4' -
NUM_5, representing the character '5' -
NUM_6, representing the character '6' -
NUM_7, representing the character '7' -
NUM_8, representing the character '8' -
NUM_9, representing the character '9' -
MINUS, representing the minus sign '-' -
PLUS, representing the plus sign '+'
-
-
If
chmatches any of the above constants, returntrueto indicate thatchis a number or a sign. -
If
chdoes not match any of the above constants, returnfalseto indicate thatchis not a number or a sign. -
End the method.

private boolean isSign(char ch) {
switch(ch) {
case MINUS:
case PLUS:
return true;
default:
return false;
}
}The isSign method in the io.nats.jparse.source.CharArrayOffsetCharSource class is used to determine whether a given character is a sign symbol. It follows these steps:
- The method takes a character
chas a parameter. - It enters a switch statement, which checks the value of
ch. - If
chis equal to theMINUSconstant or thePLUSconstant (presumably defined in the class or imported from another class), the method returnstrue. - If
chdoes not match any of the case values, the method returnsfalse.
To summarize, the isSign method checks if a character is a sign symbol (- or +) and returns true if it is, or false if it is not.

public int findFalseEnd()
@Override
public int findFalseEnd() {
if (this.data[++index] == 'a' && this.data[++index] == 'l' && this.data[++index] == 's' && this.data[++index] == 'e') {
return ++index - sourceStartIndex;
} else {
throw new UnexpectedCharacterException("Parsing JSON False Boolean", "Unexpected character", this);
}
}The findFalseEnd method in the io.nats.jparse.source.CharArrayOffsetCharSource class is defined as follows:
- The method starts by incrementing the
indexvariable and checks if the character at the updated index is equal to 'a'. - If the character is 'a', the method then increments the
indexvariable again and checks if the character at the updated index is equal to 'l'. - If the character is 'l', the method again increments the
indexvariable and checks if the character at the updated index is equal to 's'. - If the character is 's', the method once more increments the
indexvariable and checks if the character at the updated index is equal to 'e'. - If all of the characters 'a', 'l', 's', and 'e' are found consecutively, the method returns the value of the incremented
indexvariable minus thesourceStartIndexvariable. - If any of the characters are not found consecutively or the end of the source is reached before finding the complete sequence, an
UnexpectedCharacterExceptionis thrown, with the message "Parsing JSON False Boolean" and "Unexpected character", and the instance of theCharArrayOffsetCharSourceclass is passed as an argument to the exception.
public int findTrueEnd()
@Override
public int findTrueEnd() {
if (this.data[++index] == 'r' && this.data[++index] == 'u' && this.data[++index] == 'e') {
return ++index - sourceStartIndex;
} else {
throw new UnexpectedCharacterException("Parsing JSON True Boolean", "Unexpected character", this);
}
}The method findTrueEnd is implemented in the class io.nats.jparse.source.CharArrayOffsetCharSource. Its purpose is to find the end position of a boolean value "true" within a JSON source string.
Here is a step-by-step description of what the method does:
- Increment the
indexvalue by 1 and check if the character at the new index position in thedataarray is equal to 'r'. - If the character at the new index position is 'r', increment the
indexvalue by 1 again and check if the character at the new index position is equal to 'u'. - If the character at the new index position is 'u', increment the
indexvalue by 1 once more and check if the character at the new index position is equal to 'e'. - If all the characters 'r', 'u', and 'e' are found one after another, it means the end of the boolean value "true" has been found.
- Return the value of
++index - sourceStartIndex, which represents the length of the substring containing the boolean value "true".
- Return the value of
- If any of the characters is not found in the expected sequence, it means there is an unexpected character, and an exception of type
UnexpectedCharacterExceptionis thrown.- The exception message will indicate that an unexpected character was encountered while parsing the JSON True Boolean value.
- The exception will also contain a reference to the
CharArrayOffsetCharSourceobject that encountered the unexpected character.
This method is useful for parsing a JSON source string and identifying the end position of the boolean value "true".

public boolean findObjectEndOrAttributeSep()
@Override
public boolean findObjectEndOrAttributeSep() {
int i = index;
char ch = 0;
final char[] data = this.data;
final int end = sourceEndIndex;
for (; i < end; i++) {
ch = data[i];
switch(ch) {
case OBJECT_END_TOKEN:
this.index = i + 1;
return true;
case ATTRIBUTE_SEP:
this.index = i;
return false;
}
}
throw new UnexpectedCharacterException("Parsing Object Key", "Finding object end or separator", this);
}The findObjectEndOrAttributeSep method is defined in the CharArrayOffsetCharSource class in the io.nats.jparse.source package. It is used to find the end of an object or the separator within the source data.
Here is a step-by-step description of what the method does:
- The method overrides the
findObjectEndOrAttributeSepmethod defined in the superclass. - It initializes the local variables
ito the current index andchto 0. - It retrieves the source data array and assigns it to the local variable
data. - It retrieves the end index of the source and assigns it to the local variable
end. - It starts a loop from the current index
iuntil the end indexend. - Within the loop, it retrieves the character at index
ifrom the source data array and assigns it toch. - It then performs a switch-case on the character
ch. - If the character is equal to the object end token, it updates the index to
i + 1, indicating that the end of the object has been found, and returnstrue. - If the character is equal to the attribute separator, it updates the index to
i, indicating that the separator has been found, and returnsfalse. - If none of the above cases match, it continues to the next iteration of the loop.
- If the loop completes without finding the object end or separator, it throws an
UnexpectedCharacterExceptionwith an appropriate error message. - The error message specifies that the error occurred while parsing an object key and while finding the object end or separator.
- The
thisreference passed to the exception constructor refers to the currentCharArrayOffsetCharSourceinstance.
This method provides functionality to find the end of an object or the separator within the source data, allowing for efficient parsing of JSON-like data structures.

public boolean findCommaOrEndForArray()
@Override
public boolean findCommaOrEndForArray() {
int i = index;
char ch = 0;
final char[] data = this.data;
final int end = sourceEndIndex;
for (; i < end; i++) {
ch = data[i];
switch(ch) {
case ARRAY_END_TOKEN:
this.index = i + 1;
return true;
case ARRAY_SEP:
this.index = i;
return false;
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
continue;
default:
throw new UnexpectedCharacterException("Parsing Object Key", "Finding object end or separator", this, ch, i);
}
}
throw new UnexpectedCharacterException("Parsing Array", "Finding list end or separator", this);
}The findCommaOrEndForArray() method is defined in the io.nats.jparse.source.CharArrayOffsetCharSource class. It is an override method that returns a boolean value.
Here is a step-by-step description of what the findCommaOrEndForArray() method does based on its body:
- Declare a variable
iand initialize it with the currentindexvalue. - Declare a variable
chand initialize it with0. - Assign the
dataarray from the class to a local variabledata. - Extract the
endvalue from thesourceEndIndexvariable. - Start a loop from the current
indexvalue (i) to theendvalue. - Get the current character
chfromdata[i]. - Perform a switch case on
ch.- If
chis equal toARRAY_END_TOKEN:- Update the class
indexvalue toi + 1. - Return
trueto indicate that an array end has been found.
- Update the class
- If
chis equal toARRAY_SEP:- Update the class
indexvalue toi. - Return
falseto indicate that a comma separator has been found.
- Update the class
- If
chis equal to any of the whitespace characters (NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS):- Continue to the next iteration of the loop.
- If
chis not equal to any of the above characters:- Throw an
UnexpectedCharacterExceptionwith the appropriate message, indicating that an unexpected character was found while parsing the object key or finding the object end or separator.
- Throw an
- If
- If the loop completes without finding an array end or separator, throw an
UnexpectedCharacterExceptionwith the appropriate message, indicating that an unexpected character was found while parsing the array or finding the list end or separator.
public int findNullEnd()
@Override
public int findNullEnd() {
if (this.data[++index] == 'u' && this.data[++index] == 'l' && this.data[++index] == 'l') {
return ++index - sourceStartIndex;
} else {
throw new UnexpectedCharacterException("Parsing JSON Null", "Unexpected character", this);
}
}The findNullEnd method in the io.nats.jparse.source.CharArrayOffsetCharSource class is designed to find the end of the string "null" within the provided character array.
Here is the step-by-step description of what this method does:
-
The method starts with the
indexvariable pointing to the current position in the character array. -
It checks if the character at the next position in the array after
indexis 'u'. -
If the character at the next position is 'u', it then checks if the next character after 'u' is 'l'.
-
If the character at the next position after 'l' is also 'l', it means that the string "null" has been found.
-
In that case, the method returns the current
indexvalue incremented by 1 and subtracted bysourceStartIndex. This calculation gives the length of the matched "null" string within the character array. -
If the characters 'u', 'l', and 'l' are not found in sequence, it means that an unexpected character has been encountered while parsing the JSON string.
-
In such cases, the method throws an
UnexpectedCharacterException, providing a descriptive message indicating that an unexpected character was found.
In summary, the findNullEnd method searches for the string "null" within a character array and returns the length of the matched string, or throws an exception if an unexpected character is encountered.

public boolean matchChars(final int startIndex, final int endIndex, CharSequence key)
@Override
public boolean matchChars(final int startIndex, final int endIndex, CharSequence key) {
final int length = endIndex - startIndex;
final int offset = this.sourceStartIndex;
int idx = startIndex + offset;
switch(length) {
case 1:
return key.charAt(0) == data[idx];
case 2:
return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1];
case 3:
return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2];
case 4:
return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2] && key.charAt(3) == data[idx + 3];
case 5:
return key.charAt(1) == data[idx + 1] && key.charAt(3) == data[idx + 3] && key.charAt(0) == data[idx] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
case 6:
return key.charAt(0) == data[idx] && key.charAt(5) == data[idx + 5] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
case 7:
return key.charAt(0) == data[idx] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(5) == data[idx + 5] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
case 8:
return key.charAt(0) == data[idx] && key.charAt(7) == data[idx + 7] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(5) == data[idx + 5] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(4) == data[idx + 4];
case 9:
return key.charAt(0) == data[idx] && key.charAt(8) == data[idx + 8] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1];
case 10:
return key.charAt(0) == data[idx] && key.charAt(9) == data[idx + 9] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
case 11:
return key.charAt(0) == data[idx] && key.charAt(10) == data[idx + 10] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(9) == data[idx + 9] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
case 12:
return key.charAt(0) == data[idx] && key.charAt(11) == data[idx + 11] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(9) == data[idx + 9] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(10) == data[idx + 10] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
default:
final int start = 0;
final int end = length - 1;
final int middle = length / 2;
if (key.charAt(start) == data[idx] && key.charAt(end) == data[idx + end] && key.charAt(middle) == data[idx + middle]) {
for (int i = 1; i < length; i++) {
if (key.charAt(i) != data[idx + i]) {
return false;
}
}
return true;
} else {
return false;
}
}
}This method is defined in the class io.nats.jparse.source.CharArrayOffsetCharSource and is used to match a sequence of characters from the provided startIndex to endIndex with the given key. The method returns a boolean value indicating whether the characters match or not.
public boolean matchChars(final int startIndex, final int endIndex, CharSequence key)-
startIndex(int): The starting index of the character sequence to match. -
endIndex(int): The ending index of the character sequence to match. -
key(CharSequence): The key to match against the character sequence.
- Calculate the length of the character sequence by taking the difference between the
startIndexandendIndexparameters. - Get the offset from the
sourceStartIndexin the class. - Initialize the
idxvariable by adding thestartIndexto the offset. - Use a switch statement based on the length of the character sequence to handle different cases:
- If the length is 1, compare the first character of the
keywith the character atdata[idx]and return the result. - If the length is 2, compare the first two characters of the
keywith the characters atdata[idx]anddata[idx + 1]respectively and return the result. - Repeat the above steps for different cases of length 3 to 12, comparing the characters one by one.
- For any other length, do the following:
- Set the start, end, and middle indices based on the length.
- Check if the first, last, and middle characters of
keymatch the corresponding characters indata[idx]anddata[idx + end]anddata[idx + middle]respectively. - If the characters match, iterate through the remaining characters of
keyand compare them with the corresponding characters indata[idx + i]. - If any character mismatch is found, return false.
- If all characters match, return true.
- If the length is 1, compare the first character of the
- If none of the above cases match, return false.
public boolean isInteger(int startIndex, int endIndex) {
int len = endIndex - startIndex;
int offset = this.sourceStartIndex;
final char[] digitChars = data;
final boolean negative = (digitChars[startIndex] == '-');
final int cmpLen = negative ? MIN_INT_STR_LENGTH : MAX_INT_STR_LENGTH;
if (len < cmpLen)
return true;
if (len > cmpLen)
return false;
final char[] cmpStr = negative ? MIN_INT_CHARS : MAX_INT_CHARS;
for (int i = 0; i < cmpLen; ++i) {
int diff = digitChars[startIndex + i + offset] - cmpStr[i];
if (diff != 0) {
return (diff < 0);
}
}
return true;
}The method isInteger in class io.nats.jparse.source.CharArrayOffsetCharSource can be described in the following steps:
- Calculate the length of the input range given by
endIndex - startIndexand assign it to the variablelen. - Set the offset of the source index to the
sourceStartIndexof the object. - Assign the character array
datato the local variabledigitChars. - Check if the first character at the
startIndexofdigitCharsis a negative sign'-'and assign the result to thenegativevariable. - Determine the comparison length based on whether the number is negative or not. If it's negative, the comparison length should be
MIN_INT_STR_LENGTH, otherwise it should beMAX_INT_STR_LENGTH, and assign the result tocmpLen. - If the
lenis less thancmpLen, returntrueas it means the number cannot be an integer. - If the
lenis greater thancmpLen, returnfalseas it means the number cannot be an integer. - Determine the comparison string based on whether the number is negative or not. If it's negative, use
MIN_INT_CHARS, otherwise useMAX_INT_CHARS, and assign the result tocmpStr. - Loop through each character in the comparison range
(startIndex + i + offset)and compare it with the corresponding character incmpStr. - Subtract the characters from
digitCharsandcmpStrand store the difference in the variablediff. - If
diffis not equal to zero, returntrueifdiffis less than zero, indicating that the number is less than the comparison string. Otherwise, returnfalseas the number is greater than the comparison string. - If the loop completes without returning, return
trueas the number is equal to the comparison string.
public String errorDetails(String message, int index, int ch)
@Override
public String errorDetails(String message, int index, int ch) {
StringBuilder buf = new StringBuilder(255);
final char[] array = data;
buf.append(message).append("\n");
buf.append("\n");
buf.append("The current character read is " + debugCharDescription(ch)).append('\n');
int line = 0;
int lastLineIndex = 0;
for (int i = 0; i < index && i < array.length; i++) {
if (array[i] == '\n') {
line++;
lastLineIndex = i + 1;
}
}
int count = 0;
for (int i = lastLineIndex; i < array.length; i++, count++) {
if (array[i] == '\n') {
break;
}
}
buf.append("line number " + (line + 1)).append('\n');
buf.append("index number " + index).append('\n');
buf.append("offset index number " + index + sourceStartIndex).append('\n');
try {
buf.append(new String(array, lastLineIndex, count)).append('\n');
} catch (Exception ex) {
try {
int start = index = (index - 10 < 0) ? 0 : index - 10;
buf.append(new String(array, start, index)).append('\n');
} catch (Exception ex2) {
buf.append(new String(array)).append('\n');
}
}
for (int i = 0; i < (index - lastLineIndex); i++) {
buf.append('.');
}
buf.append('^');
return buf.toString();
}The errorDetails method in the CharArrayOffsetCharSource class is a method that generates an error debug message with details about the error in the source code at a given index.
Here is a step-by-step description of the method:
- Create a new
StringBuildercalledbufto store the error debug message. - Append the input
messagetobuffollowed by a new line character ("\n"). - Append an empty line to
buf. - Append a description of the current character being read, obtained from the
debugCharDescriptionmethod, tobuf. - Initialize two variables:
lineandlastLineIndex.lineis set to 0 andlastLineIndexis set to 0. - Iterate through the character array
datastarting from index 0 up to the givenindex(the index of the error in the source code). a. If the current character in the array is a new line character ('\n'), incrementlineby 1 and updatelastLineIndexto the current index plus 1. - Initialize a
countvariable to 0. - Iterate through the character array
datastarting fromlastLineIndexup to the end of the array. a. If the current character in the array is a new line character ('\n'), break the loop. b. Otherwise, incrementcountby 1. - Append the line number (calculated as
line + 1) tobuffollowed by a new line character. - Append the index number to
buffollowed by a new line character. - Append the offset index number (calculated as
index + sourceStartIndex) tobuffollowed by a new line character. - Try to append a substring of the character array
datastarting fromlastLineIndexwith a length ofcounttobuf. If an exception occurs, move to the next step. - If an exception occurs during step 12, try to append a substring of the character array
datastarting from(index - 10 < 0) ? 0 : index - 10with a length ofindextobuf. If this also fails, move to the next step. - If an exception occurs during step 13, append the entire character array
datatobuf. - Append a number of dots equal to
(index - lastLineIndex)tobuf. - Append a caret (
^) character tobuf. - Return the resulting string from
bufas the error debug message.
The Sources class provides utility methods for creating CharSource objects from various input sources, such as strings, byte arrays, files, input streams, and readers. It allows you to easily create CharSource objects from different types of input sources, including strings, byte arrays, files, input streams, and readers. It also provides different methods for creating CharSource objects from specific input types, such as CharSequence, String, byte array, char array, CharBuffer, file, input stream, and Reader. The class handles conversions and error handling for each input type, making it convenient to create CharSource objects for different use cases.
public static CharSource charSeqSource(final CharSequence source) {
if (source instanceof String) {
return new CharArrayCharSource((String) source);
} else {
return new CharArrayCharSource(source.toString());
}
}The charSeqSource method, defined in the Sources class in the io.nats.jparse.source package, is a public static method that takes a CharSequence parameter named source. The method returns a CharSource object based on the input source.
Here is a step-by-step description of what the charSeqSource method does:
-
If the
sourceparameter is an instance of theStringclass:- Create a new
CharArrayCharSourceobject, passing in thesourceparameter (which is casted to aString) as the constructor argument. - Return the newly created
CharArrayCharSourceobject.
- Create a new
-
If the
sourceparameter is not an instance of theStringclass:- Convert the
sourceparameter to a string by invoking thetoString()method on it. - Create a new
CharArrayCharSourceobject, passing in the converted string as the constructor argument. - Return the newly created
CharArrayCharSourceobject.
- Convert the
Note: The CharSource class is not defined in the given code snippet. However, it is assumed to be a class or interface that is imported and accessible within the Sources class.

public static CharSource fileSource(final String fileNameSource, final Charset charset) {
try {
return byteSource(Files.readAllBytes(Paths.get(fileNameSource)), charset);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}The fileSource method in the io.nats.jparse.source.Sources class is responsible for creating a CharSource object based on the contents of a file specified by the fileNameSource parameter.
Here are the steps performed by the fileSource method:
- The method takes two parameters:
fileNameSource, which specifies the file name or path, andcharset, which specifies the character set to use for reading the file. - Inside a try-catch block, the method calls the static method
Files.readAllBytesto read all the bytes from the file specified byfileNameSource. This method returns abyte[]array containing the contents of the file. - The
byteSourcemethod is then called, passing thebyte[]array and thecharsetparameter. This method creates and returns aCharSourceobject based on the provided byte array and character set. - If an
IOExceptionoccurs during the file reading process, the catch block catches the exception and throws a newIllegalStateExceptionwith the caught exception as the cause.
In summary, the fileSource method reads the contents of a file specified by fileNameSource and returns a CharSource object representing the file's content using the specified character set.

public static CharSource fileSource(final File fileSource, final Charset charset) {
try {
return byteSource(Files.readAllBytes(Paths.get(fileSource.getAbsolutePath())), charset);
} catch (IOException e) {
throw new IllegalStateException(e);
}
}The method fileSource defined in the class io.nats.jparse.source.Sources is used to create a CharSource from a file. Here is a step-by-step description of what the method does based on its body:
-
The method takes two parameters:
fileSourceof typeFile, which represents the file to read, andcharsetof typeCharset, which specifies the character encoding to use for reading the file. -
Inside the method, a try-catch block is used to handle any potential
IOExceptionthat might occur when reading the file. -
The method calls the
Files.readAllBytesmethod, passing in the absolute path of thefileSourcefile. This method reads all the bytes from the file and returns them as a byte array. -
The method then calls another method called
byteSource, passing in the byte array obtained from the previous step and thecharsetprovided as arguments. It is not clear from the given code snippet what thisbyteSourcemethod does, but it is likely used to convert the byte array into aCharSourceusing the specified character encoding. -
If an
IOExceptionoccurs during the file reading process, the catch block is executed. In this case, anIllegalStateExceptionis thrown, wrapping the originalIOExceptionthat was caught. -
The method ends, either returning the resulting
CharSourceif the file reading process was successful, or throwing an exception if an error occurred.
public static CharSource readerSource(final Reader readerSource) {
final BufferedReader reader = new BufferedReader(readerSource);
StringBuilder stringBuilder = new StringBuilder();
try {
String s = reader.readLine();
while (s != null) {
stringBuilder.append(s).append('\n');
s = reader.readLine();
}
} catch (Exception ex) {
throw new IllegalStateException(ex);
} finally {
try {
reader.close();
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
return new CharArrayCharSource(stringBuilder.toString());
}The readerSource method in class io.nats.jparse.source.Sources is used to convert a Reader object into a CharSource object. Here is a step-by-step description of what the method does:
-
The method takes a
Readerobject as an input parameter namedreaderSource. -
It creates a new
BufferedReaderobject namedreaderby passing thereaderSourceto its constructor. -
It creates a
StringBuilderobject namedstringBuilderto store the contents of thereader. -
The method surrounds the following code block with a try-catch block to handle any exceptions that may occur:
String s = reader.readLine(); while (s != null) { stringBuilder.append(s).append('\n'); s = reader.readLine(); }
- It initializes a
Stringvariableswith the first line read from thereaderusing thereadLine()method. - It enters a
whileloop that continues untilsisnull. - Inside the loop, it appends the value of
stostringBuilder, followed by a newline character'\n'. - It reads the next line from
readerand assigns it tos.
- It initializes a
-
If any exception occurs during the execution of the code block, an
IllegalStateExceptionis thrown, with the caught exception as its cause. -
After the try-catch block, a
finallyblock is used to ensure that thereaderis properly closed. It is closed by calling theclose()method on thereader. If anIOExceptionoccurs while closing thereader, anIllegalStateExceptionis thrown, with the caught exception as its cause. -
Finally, the method creates a new
CharArrayCharSourceobject by passing the contents ofstringBuilderas aStringto its constructor. -
The method returns the created
CharSourceobject.
This method basically reads the contents of a Reader object line by line, appends each line to a StringBuilder, and converts the resulting string into a CharSource object.

This class is a char source for char arrays. It is used by the parser to parse strings and is not thread safe. It is not a general-purpose char source.
public static String debugCharDescription(int c) {
String charString;
if (c == ' ') {
charString = "[SPACE]";
} else if (c == '\t') {
charString = "[TAB]";
} else if (c == '\n') {
charString = "[NEWLINE]";
} else if (c == ETX) {
charString = "ETX";
} else {
charString = "'" + (char) c + "'";
}
charString = charString + " with an int value of " + c;
return charString;
}This method is defined in the io.nats.jparse.source.CharArrayCharSource class. Its purpose is to return a debug description of a given character by converting it to a string representation.
-
c(int): The input character to be debugged.
- The method returns a string representation of the input character, along with additional debug information.
- Initialize the variable
charStringto store the debug description of the character. - Check if the input character
cis equal to a space character (' '). - If true, assign
"[SPACE]"tocharString. - If the character is not a space, check if it is a tab character (
' '). - If true, assign
"[TAB]"tocharString. - If the character is not a tab, check if it is a newline character (
'\n'). - If true, assign
"[NEWLINE]"tocharString. - If the character is not a newline, check if it is equal to a specific constant
ETX. - If true, assign
"ETX"tocharString. - If the character does not match any of the previous conditions, it is considered a regular character.
- Assign the character surrounded by single quotes (
') tocharString. - Concatenate the string
" with an int value of "and the value ofctocharString. - Return the value of
charStringas the debug description of the character.
public int next()
@Override
public int next() {
if (index + 1 >= data.length) {
index = data.length;
return ETX;
}
return data[++index];
}The next() method in the io.nats.jparse.source.CharArrayCharSource class is used to retrieve the next character from the source data.
Here is a step-by-step description of what this method does based on its body:
- Check if the current index (
index) plus 1 is equal to or greater than the length of thedataarray. - If the condition is true, it means that there are no more characters to read from the source data.
2.1. Set the
indexto the length of thedataarray to indicate that we have reached the end. 2.2. Return the ETX constant, which represents the end-of-transmission character. - If the condition in step 1 is false, it means that there are more characters to read from the source data.
3.1. Increment the
indexby 1. 3.2. Return the character at the newindexin thedataarray.
This method basically keeps track of the current position in the data array and returns the next character each time it is called. If there are no more characters to read, it returns the ETX constant to indicate the end of transmission.

public void checkForJunk()
@Override
public void checkForJunk() {
int index = this.index;
final char[] data = this.data;
final int length = data.length;
int ch = ETX;
for (; index < length; index++) {
ch = data[index];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
continue;
default:
throw new UnexpectedCharacterException("Junk", "Unexpected extra characters", this);
}
}
}The checkForJunk method, defined in the CharArrayCharSource class, is used to check if there are any unexpected extra characters in the data stored in the CharArrayCharSource object.
Here is a step-by-step description of what the method does based on its body:
- It begins by initializing the
indexvariable with the current index of the character being checked in the data. - It then retrieves the data stored in the
CharArrayCharSourceobject and assigns it to thedatavariable. - The length of the data is obtained and stored in the
lengthvariable. - The
chvariable is initialized with the ETX (End of Text) character. ETX typically has a value of 3. - A loop is initiated where
indexis incremented for every iteration until it reaches the length of the data. - Inside the loop, the character at the current index in the data is assigned to the
chvariable. - The
switchstatement is used to perform different actions based on the value ofch. - If
chmatches any of the four white space characters -NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS, orSPACE_WS, the loop continues to the next iteration without executing any further code. - If
chdoes not match any of the white space characters, it means that an unexpected character is found. - In such a case, an
UnexpectedCharacterExceptionis thrown with the message "Junk" and "Unexpected extra characters", along with the currentCharArrayCharSourceobject as an argument. - If the loop completes without throwing an exception, it means that there are no unexpected extra characters in the data.
public int nextSkipWhiteSpace()
@Override
public int nextSkipWhiteSpace() {
int index = this.index + 1;
final char[] data = this.data;
final int length = data.length;
int ch = ETX;
loop: for (; index < length; index++) {
ch = data[index];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
continue;
default:
break loop;
}
}
this.index = index;
return index == length ? ETX : ch;
}The method nextSkipWhiteSpace is defined in the class io.nats.jparse.source.CharArrayCharSource. Here is a step-by-step description of what this method does based on its body:
-
It overrides the method
nextSkipWhiteSpacefrom the superclass. -
It initializes a variable
indexwith the value ofthis.index + 1. -
It retrieves the character array
dataand its length from the class. -
It initializes a variable
chwith the value of ETX (end-of-text character). -
It starts a loop that iterates over the characters in the
dataarray, starting from theindexvalue. -
Inside the loop, it assigns the current character to the variable
ch. -
It uses a switch statement to check the value of
chagainst four possible whitespace characters:NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS, andSPACE_WS. -
If
chmatches any of the whitespace characters, the loop continues to the next iteration without executing the remaining code in the loop body. -
If
chdoes not match any of the whitespace characters, the loop is exited using thebreakstatement with thelooplabel. -
After the loop, the variable
indexis assigned the value of the loop index. -
The method then returns the value of
ch, unlessindexis equals tolength, in which case it returns the value of ETX.
Please note that the values ETX, NEW_LINE_WS, CARRIAGE_RETURN_WS, TAB_WS, and SPACE_WS are not defined in the given code snippet and their meanings may be specific to the context of the code.

public char skipWhiteSpace()
@Override
public char skipWhiteSpace() {
int index = this.index;
final char[] data = this.data;
final int length = data.length;
char ch;
loop: for (; index < length; index++) {
ch = data[index];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
continue;
default:
break loop;
}
}
this.index = index;
return data[index];
}The skipWhiteSpace method in the CharArrayCharSource class is used to skip any white space characters (including new lines, carriage returns, tabs, and spaces) in the character array data.
Here is a step-by-step description of what the method does:
- It starts by getting the current index from the
this.indexvariable and assigning it to a local variableindex. - It also assigns the character array data from the
this.datavariable to a local variabledata. - It gets the length of the character array and assigns it to a local variable
length. - It declares a local variable
chto hold the current character. - It starts a loop that iterates over the character array from the current index
indexup to the length of the character arraylength. - Inside the loop, it assigns the current character at the current index
indexto the variablech. - It uses a switch statement to check if the
chis a white space character (defined asNEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS, orSPACE_WS). - If the
chis a white space character, it continues to the next iteration of the loop. - If the
chis not a white space character, it breaks the loop using abreak loopstatement. - After the loop finishes, it updates the index
this.indexto the value of the local variableindex. - Finally, it returns the character
chfound at the indexindexin the character arraydata.
In summary, the skipWhiteSpace method iterates over a character array, starting from the current index, and skips any white space characters until it finds a non-white space character. It then updates the index and returns the non-white space character found.

public String toEncodedStringIfNeeded(int start, int end)
@Override
public String toEncodedStringIfNeeded(int start, int end) {
if (CharArrayUtils.hasEscapeChar(data, start, end)) {
return getEncodedString(start, end);
} else {
return this.getString(start, end);
}
}The toEncodedStringIfNeeded method defined in the CharArrayCharSource class in the io.nats.jparse.source package is responsible for converting a portion of the character array to a string, checking if any escape characters exist within the range.
Here is a step-by-step description of what the method does based on its body:
- The method overrides the
toEncodedStringIfNeededmethod from its parent class. - It takes two parameters,
startandend, which represent the start and end indices of the desired portion of the character array to convert. - The method starts by checking whether the character array within the specified range contains any escape characters using the
CharArrayUtils.hasEscapeCharmethod. - If any escape characters are found, it invokes the
getEncodedStringmethod with the samestartandendindices to return the properly encoded string. - If no escape characters are found within the specified range, it invokes the
getStringmethod with the samestartandendindices to return the string as it is without any encoding. - The method then returns the result of either the encoded or raw string based on the presence of escape characters within the specified range.
public NumberParseResult findEndOfNumberFast()
@Override
public NumberParseResult findEndOfNumberFast() {
int i = index + 1;
char ch = 0;
final char[] data = this.data;
final int length = data.length;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i, false);
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
case DECIMAL_POINT:
index = i;
return findEndOfFloatFast();
case EXPONENT_MARKER:
case EXPONENT_MARKER2:
index = i;
return parseFloatWithExponentFast();
default:
throw new IllegalStateException("Unexpected character " + ch + " at index " + index);
}
}
index = i;
return new NumberParseResult(i, false);
}This method is defined in the class io.nats.jparse.source.CharArrayCharSource and is used to find the end of a number in a character array.
Initialize the variable i to index + 1.
Initialize the variable ch to 0.
Get a reference to the character array data from this.data.
Get the length of the character array and store it in the variable length.
Start a for loop, iterating from i to length.
Inside the loop, get the character at index i and store it in the variable ch.
Use a switch statement to check for various characters:
- If
chis a whitespace character (e.g. newline, carriage return, tab, space) or one of the specified tokens (ATTRIBUTE_SEP,ARRAY_SEP,OBJECT_END_TOKEN,ARRAY_END_TOKEN), update the value ofindextoiand return a newNumberParseResultwith the updated index andfalseas the boolean value. - If
chis any of the digits (NUM_0,NUM_1,NUM_2,NUM_3,NUM_4,NUM_5,NUM_6,NUM_7,NUM_8,NUM_9), continue to the next iteration. - If
chis a decimal point (DECIMAL_POINT), update the value ofindextoiand return the result of calling the methodfindEndOfFloatFast(). - If
chis an exponent marker (EXPONENT_MARKERorEXPONENT_MARKER2), update the value ofindextoiand return the result of calling the methodparseFloatWithExponentFast(). - If none of the above conditions match, throw an
IllegalStateExceptionwith the message "Unexpected character" followed bychand the current value ofindex.
After the loop ends, update the value of index to i.
Finally, return a new NumberParseResult with i as the index and false as the boolean value.

private NumberParseResult findEndOfFloatFast() {
int i = index + 1;
char ch = 0;
final char[] data = this.data;
final int length = data.length;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i, true);
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
case EXPONENT_MARKER:
case EXPONENT_MARKER2:
index = i;
return parseFloatWithExponentFast();
default:
throw new UnexpectedCharacterException("Parsing JSON Float Number", "Unexpected character", this, ch, i);
}
}
index = i;
return new NumberParseResult(i, true);
}The method findEndOfFloatFast in class io.nats.jparse.source.CharArrayCharSource is used to find the end of a floating-point number in a character array. It returns a NumberParseResult object which contains the position of the end of the floating-point number and a flag indicating if the parsing was successful.
Here is a step-by-step description of what the method does:
- Initialize a local variable
itoindex + 1, whereindexis an instance variable representing the current position in the character array. - Initialize a local variable
chto 0. - Get a reference to the character array
datafrom thethisobject, which refers to the current instance ofCharArrayCharSource. - Get the length of the character array and store it in a local variable
length. - Start a
forloop, iterating over the characters in the character array starting fromiand going up tolength - 1. - Inside the loop, get the current character at index
iand store it in the variablech. - Use a
switchstatement to check the value ofchagainst various cases:- If
chis equal to any of the whitespace characters (NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS) or any of the JSON delimiters (ATTRIBUTE_SEP,ARRAY_SEP,OBJECT_END_TOKEN,ARRAY_END_TOKEN), then update theindexvariable toiand return a newNumberParseResultobject with the current positioniandtrueas the flag. - If
chis any of the digit characters (NUM_0toNUM_9), continue to the next iteration of the loop. - If
chis either the exponent marker character (EXPONENT_MARKER) or the second exponent marker character (EXPONENT_MARKER2), update theindexvariable toiand return the result of calling theparseFloatWithExponentFastmethod. - If none of the above cases match, throw an
UnexpectedCharacterExceptionwith the message "Parsing JSON Float Number", "Unexpected character", the current instance ofCharArrayCharSource, the unexpected characterch, and the current positioni.
- If
- After the
forloop finishes, update theindexvariable toiand return a newNumberParseResultobject with the current positioniandtrueas the flag.
private NumberParseResult parseFloatWithExponentFast() {
int i = index + 1;
char ch = 0;
int signOperator = 0;
final char[] data = this.data;
final int length = data.length;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i, true);
case MINUS:
case PLUS:
signOperator++;
if (signOperator > 1) {
throw new IllegalStateException("Too many sign operators when parsing exponent of float");
}
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
default:
throw new IllegalStateException("Unexpected character " + ch + " at index " + index);
}
}
index = i;
return new NumberParseResult(i, true);
}The method parseFloatWithExponentFast is defined in the class io.nats.jparse.source.CharArrayCharSource and returns a NumberParseResult.
Here is a step by step description of what the method is doing:
- Initialize the variable
iwith the valueindex + 1. - Initialize the variable
chwith the value0. - Initialize the variable
signOperatorwith the value0. - Get the character array
datafrom the objectthisand assign it to the variabledata. - Get the length of the character array
dataand assign it to the variablelength. - Start a loop that iterates from the value of
ito the length ofdata.- Assign the current character of
dataat indexito the variablech. - Use a switch statement to check the value of
chagainst various cases:- If
chis equal to any of the following characters:NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS,ATTRIBUTE_SEP,ARRAY_SEP,OBJECT_END_TOKEN, orARRAY_END_TOKEN, setindextoiand return a newNumberParseResultobject with the value ofiandtrue. - If
chis equal toMINUSorPLUS, incrementsignOperatorby 1. IfsignOperatoris greater than 1, throw anIllegalStateExceptionwith the message "Too many sign operators when parsing exponent of float". - If
chis any of the digits fromNUM_0toNUM_9, continue to the next iteration. - If none of the above cases match, throw an
IllegalStateExceptionwith the message "Unexpected character" followed by the value ofchand "at index" followed by the value ofindex.
- If
- Assign the current character of
- After the loop ends, set
indextoiand return a newNumberParseResultobject with the value ofiandtrue.
public int findEndOfEncodedStringFast()
@Override
public int findEndOfEncodedStringFast() {
int i = ++index;
final char[] data = this.data;
final int length = data.length;
boolean controlChar = false;
for (; i < length; i++) {
char ch = data[i];
switch(ch) {
case CONTROL_ESCAPE_TOKEN:
controlChar = !controlChar;
continue;
case STRING_END_TOKEN:
if (!controlChar) {
index = i + 1;
return i;
}
controlChar = false;
break;
default:
controlChar = false;
break;
}
}
throw new IllegalStateException("Unable to find closing for String");
}The findEndOfEncodedStringFast method in the io.nats.jparse.source.CharArrayCharSource class is used to find the index of the closing delimiter of an encoded string. Here is a step-by-step description of what this method does:
- Initialize
iwith the incrementedindexvalue. This will be the starting index for searching the encoding string. - Get the character array
datafrom the source object. - Get the length of the character array.
- Initialize a boolean variable
controlChartofalse. This variable is used to keep track of whether a control character was encountered. - Start a loop from
itolength - 1. This loop iterates over each character in the character array. - Get the character
chat indexi. - Check the value of
chusing a switch statement to handle different cases:- If
chis equal to theCONTROL_ESCAPE_TOKEN, toggle the value ofcontrolChar(i.e., change it fromtruetofalseor vice versa). - If
chis equal to theSTRING_END_TOKENandcontrolCharisfalse, update theindextoi + 1and returni. This denotes that the end of the encoding string has been found. - If
chis anything else, setcontrolChartofalse.
- If
- If no end of the encoding string is found, throw an
IllegalStateExceptionwith the message "Unable to find closing for String".
Overall, this method iterates over the characters in the input character array starting from the given index and looks for the closing delimiter of an encoded string. It handles control characters and ensures that the closing delimiter is not escaped before returning the index of the closing delimiter. If the closing delimiter is not found, it throws an exception to indicate the error.

private int findEndOfStringControlEncode(int i) {
final char[] data = this.data;
final int length = data.length;
char ch = 0;
ch = data[i];
switch(ch) {
case CONTROL_ESCAPE_TOKEN:
case STRING_END_TOKEN:
case 'n':
case 'b':
case '/':
case 'r':
case 't':
case 'f':
return i;
case 'u':
return findEndOfHexEncoding(i);
default:
throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
}
}This method is used to find the index of the closing character for a JSON string when the starting character is a control or escape character.
-
i: Index of the starting character in thedataarray.
- Get the reference to the
dataarray and the length of the array. - Initialize a
charvariablechto 0. - Assign the value of the character at index
iin thedataarray to thechvariable. - Perform a switch-case check on the value of
ch:- If
chis equal toCONTROL_ESCAPE_TOKEN,STRING_END_TOKEN,'n','b','/','r','t', or'f', return the current indexi. - If
chis equal to'u', call thefindEndOfHexEncodingmethod and return its result. - If
chdoes not match any of the above cases, throw anUnexpectedCharacterExceptionwith appropriate error message, indicating an unexpected character while finding the closing character for the JSON string.
- If
- The index of the closing character for the JSON string.
Note: The actual values for CONTROL_ESCAPE_TOKEN and STRING_END_TOKEN are not provided in the given code snippet

public int findEndOfEncodedString()
@Override
public int findEndOfEncodedString() {
int i = ++index;
final char[] data = this.data;
final int length = data.length;
char ch = 0;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case CONTROL_ESCAPE_TOKEN:
i = findEndOfStringControlEncode(i + 1);
continue;
case STRING_END_TOKEN:
index = i + 1;
return i;
default:
if (ch >= SPACE_WS) {
continue;
}
throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
}
}
throw new UnexpectedCharacterException("Parsing JSON Encoded String", "Unable to find closing for String", this, ch, i);
}The findEndOfEncodedString method is defined in the io.nats.jparse.source.CharArrayCharSource class. It overrides the findEndOfEncodedString method from its parent class.
Here is a step-by-step description of what the method is doing:
- The
indexvariable is incremented by 1 and stored in theivariable. - The
datachar array from the parent class is assigned to thedatavariable. - The length of the
dataarray is stored in thelengthvariable. - A variable
chis initialized to the value0. - A
forloop is started, iterating fromitolength. - In each iteration, the value at the current index
iin thedataarray is stored in thechvariable. - A
switchstatement is used to check the value ofch. - If
chis equal toCONTROL_ESCAPE_TOKEN, then thefindEndOfStringControlEncodemethod is called with the argumenti + 1. The returned value is then assigned back toi, and the next iteration of the loop is started. - If
chis equal toSTRING_END_TOKEN, thenindexis updated toi + 1, and the current value ofiis returned. - If
chis none of the above, it checks ifchis greater than or equal toSPACE_WS.- If it is, the loop continues to the next iteration.
- If it is not, an
UnexpectedCharacterExceptionis thrown with a message stating the unexpected character, the currentCharSource,ch, and the indexi.
- If the loop completes without finding a closing for a string, an
UnexpectedCharacterExceptionis thrown with a message stating the inability to find a closing for the string, the currentCharSource, the last value ofch, and the last value ofi.
This method is used to find the end of an encoded string in the JSON input. It iterates through the characters starting from the index position and looks for the closing token of the string or any control escape tokens. If a closing token is found, it updates the index and returns the position of the closing token. If a control escape token is found, it delegates the further handling to the findEndOfStringControlEncode method. If none of these conditions are met, it throws an exception indicating an unexpected character. If the loop completes without finding a closing token, it throws an exception indicating the inability to find a closing for the string.

private int findEndOfHexEncoding(int index) {
final char[] data = this.data;
final int length = data.length;
if (isHex(data[++index]) && isHex(data[++index]) && isHex(data[++index]) && isHex(data[++index])) {
return index;
} else {
throw new UnexpectedCharacterException("Parsing hex encoding in a string", "Unexpected character", this);
}
}The method findEndOfHexEncoding in the class io.nats.jparse.source.CharArrayCharSource is used to find the end of a hex encoding in a string. Here is a step-by-step description of what the method is doing:
-
It takes an input parameter
indexwhich represents the current position in the character array. -
It initializes a local variable
datawith the character arraythis.dataandlengthwith the length of the character array. -
It checks if the character at position
index + 1,index + 2,index + 3, andindex + 4in thedataarray are valid hexadecimal characters by calling the methodisHex(). -
If all four characters are valid hex characters, the method returns the current
indexvalue. -
If any of the characters is not a valid hex character, the method throws an exception of type
UnexpectedCharacterExceptionwith the error message "Unexpected character" and a reference to thethisobject.
In summary, the findEndOfHexEncoding method iterates over the characters in the data array starting from the index position and checks if the next four characters form a valid hex encoding. If they do, it returns the index of the last character in the encoding. If any of the characters is not valid, it throws an exception.

private boolean isHex(char datum) {
switch(datum) {
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return true;
default:
return false;
}
}The method isHex in the class io.nats.jparse.source.CharArrayCharSource is used to check if a given character is a hex digit.
Here is the step-by-step description of what the method is doing based on its body:
- Define a private boolean method named
isHexthat takes a character as input. - The method uses a switch-case statement to handle different cases of the
datumcharacter. - In the switch statement, each case represents a valid hex digit character. The valid hex digit characters are: 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', and '9'.
- If the
datumcharacter matches any of the valid hex digit characters, the method returnstrue. - If the
datumcharacter does not match any of the valid hex digit characters, the method returnsfalse. - The method is private, which means it can only be accessed within the
io.nats.jparse.source.CharArrayCharSourceclass.
That's the step-by-step description of the isHex method. It checks whether a given character is a valid hex digit character.

public int findAttributeEnd()
@Override
public int findAttributeEnd() {
int index = this.index;
final char[] data = this.data;
final int length = this.data.length;
loop: for (; index < length; index++) {
char ch = data[index];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
this.index = index;
break loop;
}
}
return index;
}The method findAttributeEnd in the class io.nats.jparse.source.CharArrayCharSource is used to find the end of an attribute within a character array.
Here are the steps performed by this method:
-
The method overrides the
findAttributeEndmethod, ensuring that it has the same signature as the overridden method in the parent class. -
The method first initializes a local variable
indexwith the value ofthis.index.this.indexrefers to the current index within the character array. -
The method then assigns the character array
datafrom the class instance to a local variabledata. -
It also assigns the length of the character array
datato a local variablelength. -
The method has a loop that iterates from the current index
indexto the length of the character arraydata. -
Inside the loop, it retrieves the character
chat the current indexindexfrom the character arraydata. -
It then checks the character
chagainst several predefined whitespace characters, likeNEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS, andATTRIBUTE_SEP. -
If the character
chmatches any of these whitespace characters, it updates thethis.indexto the current indexindexand breaks the loop using a labeledbreakstatement. -
After the loop ends, the method returns the value of
index.
To summarize, the findAttributeEnd method scans through the character array data starting from the current index this.index until it finds a whitespace character. It then returns the index where the whitespace character was found, indicating the end of the attribute.

public boolean findChar(char c)
@Override
public boolean findChar(char c) {
int index = this.index;
final char[] data = this.data;
final int length = this.data.length;
for (; index < length; index++) {
if (data[index] == c) {
this.index = index;
return true;
}
}
return false;
}The findChar method in the CharArrayCharSource class is used to find a specific character in a character array.
Here is a step-by-step description of what the method is doing:
-
The method overrides the
findCharmethod declared in the superinterface or superclass. -
The
this.indexvariable is assigned to a local variable calledindex. This is done for efficiency purposes as retrieving the instance variable directly multiple times may be costly. -
The
this.datavariable, which represents the character array being searched, is assigned to a local variable calleddata. -
The
lengthvariable is assigned the length of thedatacharacter array. -
A
forloop is started withindexbeing the starting point of the loop andlengthbeing the end condition. -
Inside the loop, the current character at the
indexposition of thedataarray is compared to the charactercthat is being searched for. -
If the characters match, the
this.indexinstance variable is updated with the currentindexvalue, and the method returnstrueindicating that the character was found. -
If the loop completes without finding a matching character, the method returns
falseindicating that the character was not found in the array.
Please note that this step-by-step description assumes that the instance variables (this.index, this.data, etc.) are properly initialized before using the findChar method.

public int findEndString()
@Override
public int findEndString() {
int i = ++index;
final char[] data = this.data;
final int length = data.length;
char ch = 0;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case STRING_END_TOKEN:
index = i;
return i;
default:
if (ch >= SPACE_WS) {
continue;
}
throw new UnexpectedCharacterException("Parsing JSON String", "Unexpected character while finding closing for String", this, ch, i);
}
}
throw new UnexpectedCharacterException("Parsing JSON String", "Unable to find closing for String", this, ch, i);
}The findEndString method in the CharArrayCharSource class is used to find the end of a JSON string within a given character array.
Here is a step-by-step description of what the method is doing:
- Increment the
indexby 1 and assign it to a local variablei. - Retrieve the character array
datafrom the currentCharArrayCharSourceobject. - Get the length of the character array and assign it to a local variable
length. - Initialize a variable
chwith a value of 0. - Start a loop from the current
index(i) until the end of the character array. - Within the loop, retrieve the character at position
ifrom the character array and assign it toch. - Use a switch statement to check the value of
ch.- If
chis equal to a constant variableSTRING_END_TOKEN, update theindexwith the current value ofiand returnias the index of the end of the string. - If
chis not equal toSTRING_END_TOKEN, check ifchis greater than or equal to a constant variableSPACE_WS(a whitespace character).- If it is greater than or equal to
SPACE_WS, continue to the next iteration of the loop. - If it is not greater than or equal to
SPACE_WS, throw anUnexpectedCharacterExceptionwith a message indicating that an unexpected character was found while finding the closing for the string.
- If it is greater than or equal to
- If
- If the end of the character array is reached without finding the closing for the string, throw an
UnexpectedCharacterExceptionwith a message indicating that the closing for the string was not found.
In summary, this method iterates over the character array starting from the current index, looking for the end of a JSON string. If the end of the string is found, the method returns the index of the closing character. If an unexpected character is encountered, an exception is thrown. If the closing for the string is not found, an exception is also thrown.

public NumberParseResult findEndOfNumber()
@Override
public NumberParseResult findEndOfNumber() {
final char startCh = getCurrentChar();
final int startIndex = index;
char ch = startCh;
int i = index + 1;
final char[] data = this.data;
final int length = data.length;
loop: for (; i < length; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
break loop;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
case DECIMAL_POINT:
if (startCh == MINUS) {
final int numLenSoFar = i - startIndex;
if (numLenSoFar == 1) {
throw new UnexpectedCharacterException("Parsing JSON Number", "Unexpected character", this, ch, i);
}
}
index = i;
return findEndOfFloat();
case EXPONENT_MARKER:
case EXPONENT_MARKER2:
index = i;
return parseFloatWithExponent();
default:
throw new UnexpectedCharacterException("Parsing JSON Number", "Unexpected character", this, ch, i);
}
}
index = i;
final int numLength = i - startIndex;
switch(startCh) {
case NUM_0:
if (numLength != 1) {
throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't start with a 0 ", this, startCh, startIndex);
}
break;
case PLUS:
throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't start with a plus ", this, startCh, startIndex);
case MINUS:
switch(numLength) {
case 1:
throw new UnexpectedCharacterException("Parsing JSON Int Number", "Int can't be only a minus, number is missing", this, startCh, startIndex);
case 2:
break;
default:
if (data[startIndex + 1] == NUM_0) {
throw new UnexpectedCharacterException("Parsing JSON Int Number", "0 can't be after minus sign", this, startCh, startIndex);
}
}
}
return new NumberParseResult(i, false);
}The findEndOfNumber method is defined in the io.nats.jparse.source.CharArrayCharSource class. This method is used to find the end index of a number in a character array source.
Here is a step-by-step description of what the method is doing:
- It starts by getting the current character from the character array source (
getCurrentChar()). - It initializes the
startChvariable with the current character and thestartIndexvariable with the current index. - It then enters a loop starting from
i = index + 1untili < length(wherelengthis the length of the character array). - Inside the loop, it assigns the next character (
data[i]) to thechvariable. - It then performs a switch case on the
chvariable to check for various characters and perform different actions:- If the character is one of the whitespace characters (
NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS), one of the separators (ATTRIBUTE_SEP,ARRAY_SEP), or one of the end tokens (OBJECT_END_TOKEN,ARRAY_END_TOKEN), it breaks out of the loop. - If the character is one of the digits (
NUM_0toNUM_9), it continues to the next iteration of the loop. - If the character is a decimal point (
DECIMAL_POINT), it checks if thestartChis a minus sign (MINUS). If it is, it throws an exception if the length of the number so far is 1. It then sets theindextoiand returns the result of calling thefindEndOfFloatmethod. - If the character is an exponent marker (
EXPONENT_MARKERorEXPONENT_MARKER2), it sets theindextoiand returns the result of calling theparseFloatWithExponentmethod. - If none of the above cases match, it throws an exception for an unexpected character.
- If the character is one of the whitespace characters (
- After the loop, it sets the
indextoi(the current index) and calculates the length of the number (numLength) by subtracting thestartIndexfromi. - It then performs a switch case on the
startChvariable to check for different cases:- If the
startChisNUM_0and the length of the number is not 1, it throws an exception for an integer number starting with 0. - If the
startChis a plus sign (PLUS), it throws an exception for an integer number starting with a plus sign. - If the
startChis a minus sign (MINUS), it checks the length of the number:- If the length is 1, it throws an exception for a minus sign without a number.
- If the length is 2, it continues to the next step.
- If the length is greater than 2 and the character after the minus sign is
NUM_0, it throws an exception for 0 being after a minus sign.
- If the
- Finally, it returns a new
NumberParseResultobject with the end index (i) and a boolean indicating whether the number is a float (false).
private NumberParseResult findEndOfFloat() {
int i = index + 1;
char ch = (char) next();
if (!isNumber(ch)) {
throw new UnexpectedCharacterException("Parsing float part of number", "After decimal point expecting number but got", this, ch, this.index);
}
final char[] data = this.data;
final int length = data.length;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i, true);
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
case EXPONENT_MARKER:
case EXPONENT_MARKER2:
index = i;
return parseFloatWithExponent();
default:
throw new UnexpectedCharacterException("Parsing JSON Float Number", "Unexpected character", this, ch, i);
}
}
index = i;
return new NumberParseResult(i, true);
}The findEndOfFloat method is a private method defined in the io.nats.jparse.source.CharArrayCharSource class. It is responsible for finding the end of a floating-point number within a JSON string.
Here is a step-by-step description of what the method does based on its body:
-
The method starts by initializing a local variable
iwith the value ofindex + 1. -
It then retrieves the next character
chfrom the input stream by calling thenext()method. -
It checks if
chis a valid number character by calling theisNumber()method. If it is not a valid number character, it throws anUnexpectedCharacterExceptionwith an appropriate error message. -
Next, the method accesses the
dataarray andlengthof the array from the parent object. -
It enters a
forloop that iterates fromitolength-1. -
Inside the loop, it gets the character
chat the current indexifrom thedataarray. -
It then performs a
switchstatement onchto handle different types of characters:-
If
chis one of the whitespace characters or special tokens (e.g., newline, tab, comma, array or object end token), it sets theindextoiand returns a newNumberParseResultobject with the current index andtruevalue indicating that the float number has been successfully parsed. -
If
chis one of the numeric digits (0-9), it continues the loop without performing any action. -
If
chis an exponent marker (e.g., 'E' or 'e'), it sets theindextoiand calls theparseFloatWithExponentmethod to handle parsing of the floating-point number with an exponent. -
If
chis any other character, it throws anUnexpectedCharacterExceptionwith an appropriate error message.
-
-
After the loop, it sets the
indextoiand returns a newNumberParseResultobject with the current index andtruevalue indicating that the float number has been successfully parsed.
In summary, the findEndOfFloat method iterates through the characters of the input string starting from the index + 1 position. It checks each character to determine if it is a valid part of a floating-point number, until it reaches a character that is not part of the number. It returns the index of the last character of the number and whether or not the number was successfully parsed.

private boolean isNumber(final char ch) {
switch(ch) {
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
return true;
default:
return false;
}
}The isNumber method is defined within the io.nats.jparse.source.CharArrayCharSource class. It determines whether a given character is a number or not.
- Type:
char - Description: The character that needs to be checked.
- The method takes a character
chas input. - It uses a switch statement to compare the input character with a set of predefined constants representing the digits 0 to 9.
- If the input character matches any of the predefined constants, the method returns
true, indicating that the character is a number. - If the input character does not match any of the predefined constants, the method returns
false, indicating that the character is not a number.
private NumberParseResult parseFloatWithExponent() {
char ch = (char) next();
if (!isNumberOrSign(ch)) {
throw new UnexpectedCharacterException("Parsing exponent part of float", "After exponent expecting number or sign but got", this, ch, this.index);
}
if (isSign(ch)) {
ch = (char) next();
if (!isNumber(ch)) {
throw new UnexpectedCharacterException("Parsing exponent part of float after sign", "After sign expecting number but got", this, ch, this.index);
}
}
int i = index + 1;
final char[] data = this.data;
final int length = data.length;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
case ATTRIBUTE_SEP:
case ARRAY_SEP:
case OBJECT_END_TOKEN:
case ARRAY_END_TOKEN:
index = i;
return new NumberParseResult(i, true);
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
break;
default:
throw new UnexpectedCharacterException("Parsing Float with exponent", "Unable to find closing for Number", this, ch, i);
}
}
index = i;
return new NumberParseResult(i, true);
}The method parseFloatWithExponent() in class io.nats.jparse.source.CharArrayCharSource is used to parse a floating-point number with an exponent.
Here is a step-by-step description of what the method does based on its body:
- It retrieves the next character from the input and assigns it to the variable
ch. - It checks if the character
chis a number or a sign. If it is not, it throws anUnexpectedCharacterExceptionwith an error message indicating that it was expecting a number or sign. - If the character
chis a sign, it retrieves the next character from the input and assigns it toch. Then, it checks ifchis a number. If it is not, it throws anUnexpectedCharacterExceptionwith an error message indicating that it was expecting a number after the sign. - It initializes an integer variable
iwithindex + 1. This will be used to iterate through the characters in the data array. - It retrieves the data array and its length and assigns them to
dataandlengthvariables respectively. - It enters a loop that starts at
iand iterates untilireaches the end of the data array. - Inside the loop, it assigns the current character at index
itoch. - It then checks the value of
chagainst a set of characters representing whitespace, separators, and the end of objects/arrays. If a match is found, it updates the value ofindextoiand returns a newNumberParseResultobject with the current index and a flag indicating successful parsing. - If
chis a digit (0-9), it continues to the next iteration of the loop. - If
chdoes not match any of the previous cases, it throws anUnexpectedCharacterExceptionwith an error message indicating that it was unable to find a closing character for the number. - After the loop ends, it updates the value of
indextoiand returns a newNumberParseResultobject with the current index and a flag indicating successful parsing.
private boolean isNumberOrSign(char ch) {
switch(ch) {
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
return true;
default:
return false;
}
}Method: isNumberOrSign
This method is defined in the io.nats.jparse.source.CharArrayCharSource class and is used to determine if a given character is either a number or a sign (+ or -).
Algorithm:
- Accept a character
chas input. - Perform a switch case on the character
ch. - Check if
chmatches any of the following cases:- If
chis equal to the character constantNUM_0 - If
chis equal to the character constantNUM_1 - If
chis equal to the character constantNUM_2 - If
chis equal to the character constantNUM_3 - If
chis equal to the character constantNUM_4 - If
chis equal to the character constantNUM_5 - If
chis equal to the character constantNUM_6 - If
chis equal to the character constantNUM_7 - If
chis equal to the character constantNUM_8 - If
chis equal to the character constantNUM_9 - If
chis equal to the character constantMINUS - If
chis equal to the character constantPLUS
- If
- If
chmatches any of the above cases, returntrue. - If
chdoes not match any of the above cases, returnfalse.
private boolean isSign(char ch) {
switch(ch) {
case MINUS:
case PLUS:
return true;
default:
return false;
}
}The isSign method in the CharArrayCharSource class is used to determine if a given character is a sign symbol.
Here is a step-by-step description of what the method does:
- The method takes a single character (
ch) as input. - It uses a switch statement to check the value of
ch. - If the value of
chis equal to the constantMINUS, which represents a minus sign, or the constantPLUS, which represents a plus sign, it returnstrue. - If the value of
chdoes not match any of the cases in the switch statement, it returnsfalse.
In summary, the isSign method checks if a given character is a sign symbol (minus or plus) and returns true if it is or false if it isn't.

public int findFalseEnd()
@Override
public int findFalseEnd() {
if (this.data[++index] == 'a' && this.data[++index] == 'l' && this.data[++index] == 's' && this.data[++index] == 'e') {
return ++index;
} else {
throw new UnexpectedCharacterException("Parsing JSON False Boolean", "Unexpected character", this);
}
}The findFalseEnd method defined in the CharArrayCharSource class, located at io.nats.jparse.source.CharArrayCharSource, performs the following steps:
- The method overrides the
findFalseEndmethod, which is declared in a superclass. - It starts by checking if the character at the next index (
++index) in thedataarray is equal to the character'a'. - If the above condition is true, it also checks if the character at the next index is
'l','s', and'e'respectively. - If all the characters
'a','l','s', and'e'are found consecutively, it returns the incremented index value. - If any of the characters are not found consecutively, it throws an
UnexpectedCharacterException. - The
UnexpectedCharacterExceptiontakes the following parameters:"Parsing JSON False Boolean"as the error message,"Unexpected character"as the detailed error description, and the currentCharArrayCharSourceinstance (this) where the exception occurred.
Please note that the ++index operator increments the index value and returns the incremented value.

public int findTrueEnd()
@Override
public int findTrueEnd() {
if (this.data[++index] == 'r' && this.data[++index] == 'u' && this.data[++index] == 'e') {
return ++index;
} else {
throw new UnexpectedCharacterException("Parsing JSON True Boolean", "Unexpected character", this);
}
}The findTrueEnd method in the io.nats.jparse.source.CharArrayCharSource class is used to determine the end position of the "true" boolean value in a JSON document.
Here is a step-by-step breakdown of how the method works:
- The method overrides the
findTrueEndmethod defined in the superclass. - The method begins by incrementing the
indexvariable using the++indexsyntax. - It then checks if the character at the current
indexin thedataarray is equal to the character 'r'. - If it is, the method proceeds to the next step.
- The method then increments the
indexvariable again and checks if the character at the newindexis equal to the character 'u'. - If it is, the method proceeds to the next step.
- The method increments the
indexvariable once more and checks if the character at the newindexis equal to the character 'e'. - If it is, the method increments the
indexagain and returns the newindexvalue. - If any of the checks made in steps 3, 5, or 7 fail, it means that there is an unexpected character in the input, and the method throws an
UnexpectedCharacterException. - The
UnexpectedCharacterExceptionis constructed with a message indicating that it occurred while parsing a JSON True Boolean and providing the information about the unexpected character and the current source. - The exception is thrown, and the execution of the method is stopped.
This findTrueEnd method allows the caller to locate the true boolean value in a JSON document and determine its end position.

public boolean findObjectEndOrAttributeSep()
@Override
public boolean findObjectEndOrAttributeSep() {
int i = index;
char ch = 0;
final char[] data = this.data;
final int length = data.length;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case OBJECT_END_TOKEN:
this.index = i + 1;
return true;
case ATTRIBUTE_SEP:
this.index = i;
return false;
}
}
throw new UnexpectedCharacterException("Parsing Object Key", "Finding object end or separator", this);
}The method findObjectEndOrAttributeSep in the class io.nats.jparse.source.CharArrayCharSource is used to search for either the end of an object or an attribute separator in a character array.
Here is a step-by-step description of what this method is doing:
- Set the initial value of the variable
ito the current index value. - Set the initial value of the variable
chto zero. - Get the reference to the character array
dataand the length of the array. - Start a loop to iterate through the elements of the character array, starting from the current index
iand ending at the last element of the array. - Within the loop, assign the current element of the character array to the variable
ch. - Use a switch statement to check the value of
chagainst two possible cases: a. Ifchmatches the constantOBJECT_END_TOKEN, update the current indexindextoi + 1and returntrueto indicate that the end of an object has been found. b. Ifchmatches the constantATTRIBUTE_SEP, update the current indexindextoiand returnfalseto indicate that an attribute separator has been found. - If none of the above cases match for any element of the character array, throw an
UnexpectedCharacterExceptionwith a detailed message indicating that the method was trying to parse an object key, while searching for either the object end or separator. - End of the loop.
In summary, the method iterates through the character array data starting from the current index index and checks if each character matches either the object end token or the attribute separator. If a match is found, it updates the current index and returns a boolean value indicating the result. If no match is found, it throws an exception.

public boolean findCommaOrEndForArray()
@Override
public boolean findCommaOrEndForArray() {
int i = index;
char ch = 0;
final char[] data = this.data;
final int length = data.length;
for (; i < length; i++) {
ch = data[i];
switch(ch) {
case ARRAY_END_TOKEN:
this.index = i + 1;
return true;
case ARRAY_SEP:
this.index = i;
return false;
case NEW_LINE_WS:
case CARRIAGE_RETURN_WS:
case TAB_WS:
case SPACE_WS:
continue;
default:
throw new UnexpectedCharacterException("Parsing Object Key", "Finding object end or separator", this, ch, i);
}
}
throw new UnexpectedCharacterException("Parsing Array", "Finding list end or separator", this);
}The findCommaOrEndForArray method in the CharArrayCharSource class is used to find the comma or end token within an array. Here is a step-by-step description of what the method does:
- Start at the current index stored in the
indexvariable. - Initialize a temporary variable
chto store the current character being examined. - Get the character array
datafrom the instance variablethis.data. - Get the length of the character array in the
lengthvariable. - Start a loop that iterates from the current index (
i) to the length of the character array. - Get the character at the current index (
i) and store it in thechvariable. - Use a switch statement to check the value of
ch. - If the character is equal to the
ARRAY_END_TOKEN, set theindexvariable toi + 1, indicating that the end of the array has been found. Then, returntrueto indicate that the end token has been found. - If the character is equal to the
ARRAY_SEP, set theindexvariable toi, indicating that a comma separator has been found. Then, returnfalseto indicate that a separator has been found. - If the character is one of the defined whitespace characters (
NEW_LINE_WS,CARRIAGE_RETURN_WS,TAB_WS,SPACE_WS), skip the current iteration of the loop and continue to the next character. - If the character does not match any of the expected values, throw an
UnexpectedCharacterExceptionwith the appropriate error message and include information about the current character and its index. - If the end of the array is reached without finding an end token or separator, throw an
UnexpectedCharacterExceptionwith the appropriate error message and context information about the parsing operation.
This method is used to parse an input character array and determine whether the next character is an end token or a separator within an array, based on the defined array tokens and whitespace characters. It returns a boolean value indicating whether an end token has been found or not.

public int findNullEnd()
@Override
public int findNullEnd() {
if (this.data[++index] == 'u' && this.data[++index] == 'l' && this.data[++index] == 'l') {
return ++index;
} else {
throw new UnexpectedCharacterException("Parsing JSON Null", "Unexpected character", this);
}
}The findNullEnd method in the CharArrayCharSource class is used to find the end position of a "null" value in a JSON string.
Here is a step-by-step description of what the method does:
-
The method overrides the
findNullEndmethod defined in the superclass, indicating that it provides a specific implementation for this method. -
The method begins by incrementing the value of the
indexvariable by 1. This is done using the pre-increment operator++before theindexvariable. This means that the new value ofindexwill be one greater than its previous value. -
The method then checks if the character at the new
indexposition in thedataarray is equal to the character 'u'. If it is, the condition is true and the code block inside the if statement is executed. -
Inside the if statement, the value of
indexis again incremented by 1 using the pre-increment operator. This means that the new value ofindexwill be one greater than its previous value. -
The method then checks if the character at the new
indexposition in thedataarray is equal to the character 'l'. If it is, the condition is true and the code block inside the if statement is executed. -
Inside the if statement, the value of
indexis again incremented by 1 using the pre-increment operator. This means that the new value ofindexwill be one greater than its previous value. -
The method then checks if the character at the new
indexposition in thedataarray is equal to the character 'l'. If it is, the condition is true and the code block inside the if statement is executed. -
Inside the if statement, the value of
indexis once again incremented by 1 using the pre-increment operator. This means that the new value ofindexwill be one greater than its previous value. -
After the if-else block, the method returns the value of
index, incremented by 1 using the pre-increment operator. This means that the returned value will be one greater than its previous value. -
If any of the if conditions in steps 3, 5, or 7 evaluate to false, indicating that the "null" value was not found, an
UnexpectedCharacterExceptionis thrown. This exception provides an error message stating that "Parsing JSON Null" failed because an unexpected character was encountered in theCharArrayCharSource, and includes a reference to the source object.
In summary, the findNullEnd method in the CharArrayCharSource class is responsible for locating the end position of a "null" value in a JSON string. It checks if the characters at a specific position in the string match the sequence 'u', 'l', 'l', and returns the position of the last character of the match. If the expected sequence is not found, an exception is thrown.

public boolean matchChars(final int startIndex, final int endIndex, CharSequence key)
@Override
public boolean matchChars(final int startIndex, final int endIndex, CharSequence key) {
final int length = endIndex - startIndex;
int idx = startIndex;
switch(length) {
case 1:
return key.charAt(0) == data[idx];
case 2:
return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1];
case 3:
return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2];
case 4:
return key.charAt(0) == data[idx] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2] && key.charAt(3) == data[idx + 3];
case 5:
return key.charAt(1) == data[idx + 1] && key.charAt(3) == data[idx + 3] && key.charAt(0) == data[idx] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
case 6:
return key.charAt(0) == data[idx] && key.charAt(5) == data[idx + 5] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
case 7:
return key.charAt(0) == data[idx] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(5) == data[idx + 5] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4];
case 8:
return key.charAt(0) == data[idx] && key.charAt(7) == data[idx + 7] && key.charAt(3) == data[idx + 3] && key.charAt(1) == data[idx + 1] && key.charAt(5) == data[idx + 5] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(4) == data[idx + 4];
case 9:
return key.charAt(0) == data[idx] && key.charAt(8) == data[idx + 8] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1];
case 10:
return key.charAt(0) == data[idx] && key.charAt(9) == data[idx + 9] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
case 11:
return key.charAt(0) == data[idx] && key.charAt(10) == data[idx + 10] && key.charAt(6) == data[idx + 6] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(9) == data[idx + 9] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
case 12:
return key.charAt(0) == data[idx] && key.charAt(11) == data[idx + 11] && key.charAt(3) == data[idx + 3] && key.charAt(7) == data[idx + 7] && key.charAt(2) == data[idx + 2] && key.charAt(6) == data[idx + 6] && key.charAt(9) == data[idx + 9] && key.charAt(4) == data[idx + 4] && key.charAt(5) == data[idx + 5] && key.charAt(10) == data[idx + 10] && key.charAt(1) == data[idx + 1] && key.charAt(8) == data[idx + 8];
default:
final int start = 0;
final int end = length - 1;
final int middle = length / 2;
if (key.charAt(start) == data[idx] && key.charAt(end) == data[idx + end] && key.charAt(middle) == data[idx + middle]) {
for (int i = 1; i < length; i++) {
if (key.charAt(i) != data[idx + i]) {
return false;
}
}
return true;
} else {
return false;
}
}
}The matchChars method is a method defined in the CharArrayCharSource class, which is used for comparing a character sequence with a portion of a character array.
Here's a step-by-step description of what the method does:
-
The method takes three parameters:
startIndex,endIndex, andkey. These parameters indicate the range of the character array to be compared and the character sequence to compare it with. -
The method calculates the length of the character array range by subtracting the
startIndexfrom theendIndex. -
It initializes a variable
idxwith the value of thestartIndex. -
The method then uses a
switchstatement based on the length of the character array range:-
For lengths 1 to 12, it compares each corresponding character in the
keysequence with the corresponding character in the character array range using thecharAtmethod. If all the characters match, it returnstrue, otherwisefalse. -
For lengths greater than 12, it performs a more generic comparison. It checks if the first, middle, and last characters of the
keysequence match the corresponding characters in the character array range. If they do, it iterates through the rest of the characters in thekeysequence and character array range, comparing each character. If all the characters match, it returnstrue, otherwisefalse. -
If none of the above cases match, it returns
false.
-
Overall, the matchChars method is used to determine if a given character sequence matches a specific portion of a character array. It uses a combination of specific comparisons for shorter lengths and a more generic comparison for longer lengths.

public boolean isInteger(int offset, int end) {
int len = end - offset;
final char[] digitChars = data;
final boolean negative = (digitChars[offset] == '-');
final int cmpLen = negative ? MIN_INT_STR_LENGTH : MAX_INT_STR_LENGTH;
if (len < cmpLen)
return true;
if (len > cmpLen)
return false;
final char[] cmpStr = negative ? MIN_INT_CHARS : MAX_INT_CHARS;
for (int i = 0; i < cmpLen; ++i) {
int diff = digitChars[offset + i] - cmpStr[i];
if (diff != 0) {
return (diff < 0);
}
}
return true;
}The isInteger method, defined in the io.nats.jparse.source.CharArrayCharSource class, determines whether a sequence of characters in an array represents an integer. The method takes in two parameters - offset and end, which specify the range of characters in the array to be considered.
Here is a step-by-step description of what the method does based on its body:
- Calculate the length of the sequence by subtracting the
offsetfrom theendparameter and store it in thelenvariable. - Get a reference to the character array (
data) that contains the sequence of characters to be examined. - Determine whether the first character in the sequence is a negative sign ('-') and store the result in the
negativevariable. - Determine whether the length of the sequence (
len) is less than a predefined length for comparisons (MIN_INT_STR_LENGTHorMAX_INT_STR_LENGTH). If it is, returntruesince the sequence is shorter than the minimum length required for a valid integer representation. - If the length of the sequence is longer than the predefined length, return
falsesince the sequence is longer than the maximum length required for a valid integer representation. - Determine which predefined character array to use for comparison (
MIN_INT_CHARSorMAX_INT_CHARS), based on whether the sequence represents a negative or positive integer, and store it in thecmpStrvariable. - Iterate over each character in the sequence, comparing it with the corresponding character in the predefined character array.
- In each iteration, calculate the difference between the current character in the sequence and the corresponding character in the predefined character array and store it in the
diffvariable. - If the difference is non-zero, return
trueif the difference is less than zero, indicating that the sequence is a smaller number than the predefined comparison value. - If all characters in the sequence match the corresponding characters in the predefined character array, return
trueto indicate that the sequence represents a valid integer. - If no non-zero differences are found, return
truesince the sequence matches the predefined comparison value.
In summary, the isInteger method determines whether a sequence of characters in an array represents an integer by comparing it with predefined character arrays and performing character-by-character comparisons. It handles cases where the sequence is too short or too long, and also distinguishes between negative and positive integers.

public String errorDetails(String message, int index, int ch)
@Override
public String errorDetails(String message, int index, int ch) {
StringBuilder buf = new StringBuilder(255);
final char[] array = data;
buf.append(message).append("\n");
buf.append("\n");
buf.append("The current character read is " + debugCharDescription(ch)).append('\n');
int line = 0;
int lastLineIndex = 0;
for (int i = 0; i < index && i < array.length; i++) {
if (array[i] == '\n') {
line++;
lastLineIndex = i + 1;
}
}
int count = 0;
for (int i = lastLineIndex; i < array.length; i++, count++) {
if (array[i] == '\n') {
break;
}
}
buf.append("line number " + (line + 1)).append('\n');
buf.append("index number " + index).append('\n');
try {
buf.append(new String(array, lastLineIndex, count)).append('\n');
} catch (Exception ex) {
try {
int start = index = (index - 10 < 0) ? 0 : index - 10;
buf.append(new String(array, start, index)).append('\n');
} catch (Exception ex2) {
buf.append(new String(array)).append('\n');
}
}
for (int i = 0; i < (index - lastLineIndex); i++) {
buf.append('.');
}
buf.append('^');
return buf.toString();
}This method, defined in the class io.nats.jparse.source.CharArrayCharSource, is used to generate an error message with details about the error encountered at a specific index in the character array.
public String errorDetails(String message, int index, int ch)-
message(String): A custom error message to prepend to the error details. -
index(int): The index at which the error occurred in the character array. -
ch(int): The current character being processed when the error occurred.
-
String: The generated error message with details.
- Create a
StringBuilderinstance namedbuf, initialized with an initial capacity of 255. - Create a local variable named
arrayof typechar[], initialized with the character arraydatafrom the class. - Append the
messageparameter and a newline character tobuf. - Append an additional newline character to
buf. - Append a formatted string to
bufthat describes the current character being processed, using thedebugCharDescriptionmethod. - Initialize two local variables,
lineandlastLineIndex, both set to 0. - Iterate from
i= 0 toindex, exclusive, and as long asiis within the length ofarray.- If the character
array[i]is a newline character, incrementlineby 1 and updatelastLineIndextoi + 1.
- If the character
- Initialize two local variables,
countset to 0, andiset tolastLineIndex. - Iterate from
i=lastLineIndexto the end ofarray.- If the character
array[i]is a newline character, break the loop. - Otherwise, increment
countby 1.
- If the character
- Append a formatted string to
bufthat states the line number, which isline + 1. - Append a formatted string to
bufthat states the index number, which isindex. - Attempt the following block, and catch any exceptions thrown:
- Append a substring of
arraytobuf, starting atlastLineIndexwith a length ofcount.
- Append a substring of
- If an exception was caught in the above block, attempt the following block, and catch any exceptions thrown:
- Calculate the start index by subtracting 10 from
index. If the result is less than 0, setstartto 0. - Append a substring of
arraytobuf, starting atstartwith a length ofindex.
- Calculate the start index by subtracting 10 from
- If an exception was caught in the above block, append the entire
arraytobuf. - Append a sequence of dots (
.) tobuf, equal to the difference betweenindexandlastLineIndex. - Append a
^character tobuf. - Return the string representation of
buf.

The ParseFloat class is a public class that is used for parsing floating-point values.
public static float parseFloat(char[] chars, int startIndex, int endIndex) {
boolean negative = false;
int i = startIndex;
float result = 0;
// Check for a negative sign
if (chars[i] == '-') {
negative = true;
i++;
}
loop: while (i < endIndex) {
char ch = chars[i];
switch(ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
result = result * 10 + (ch - '0');
i++;
break;
case '.':
result = parseFractionPart(i + 1, endIndex, chars, result);
break loop;
case 'e':
result = parseExponent(i + 1, endIndex, chars, result);
break loop;
default:
throw new UnexpectedCharacterException("parsing float", "Illegal character", ch, i);
}
}
if (negative) {
result = -result;
}
return result;
}The parseFloat method in the io.nats.jparse.source.support.ParseFloat class is a static method that takes three parameters: char[] chars, int startIndex, and int endIndex. It returns a float value.
Here is a step-by-step description of what the parseFloat method does based on its body:
-
It initializes a boolean variable
negativetofalse, an integer variableito the value ofstartIndex, and a float variableresultto0. -
It checks if the character at index
iin thecharsarray is'-'. If it is, it setsnegativetotrueand incrementsi` by 1. -
It enters a loop that continues until
iis less thanendIndex. -
Inside the loop, it assigns the character at index
iin thecharsarray to a char variablech. -
It checks the value of
chusing a switch statement. Ifchis a digit from 0 to 9, it performs the following steps:- Multiplies the
resultby 10 and adds the numeric value ofchminus the character '0' (to convert from ASCII to the actual numeric value). - Increments
iby 1. - Breaks out of the switch statement.
- Multiplies the
-
If
chis a '.', it calls a methodparseFractionPartwith parametersi + 1,endIndex,chars, andresultand assigns the return value toresult. -
If
chis an 'e', it calls a methodparseExponentwith parametersi + 1,endIndex,chars, andresultand assigns the return value toresult. -
If
chdoes not match any of the cases in the switch statement, it throws anUnexpectedCharacterExceptionwith the message "Illegal character" and the values of "parsing float", the actual characterch, and the indexi. -
After the loop ends, it checks if
negativeistrue. If it is, it negates the value ofresult. -
Finally, it returns the value of
result.
Note: The parseFractionPart and parseExponent methods are not included in the given code, so their behavior is not described here.

private static float parseFractionPart(int i, int endIndex, char[] chars, float result) {
float fraction = 0.1f;
while (i < endIndex) {
char ch = chars[i];
switch(ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
result += (ch - '0') * fraction;
fraction /= 10;
i++;
break;
case 'e':
return parseExponent(i + 1, endIndex, chars, result);
default:
throw new UnexpectedCharacterException("float parsing fraction part", "Illegal character", ch, i);
}
}
return result;
}The parseFractionPart method, defined in the ParseFloat class of the io.nats.jparse.source.support package, is used to parse and calculate the fraction part of a floating-point number.
Here is a step-by-step description of what the method is doing:
-
The method takes the following parameters:
i(the starting index of the fraction part),endIndex(the index at which the fraction part ends),chars(an array of characters representing the input number), andresult(the current result of the parsing operation). -
It initializes a variable
fractionas 0.1. -
It enters a
whileloop that iterates fromitoendIndex. -
Within the loop, the method retrieves the character at the current index (
i) from thecharsarray and assigns it to a variablech. -
It uses a
switchstatement to perform different actions based on the characterch. -
If the character
chis a digit ('0','1','2','3','4','5','6','7','8','9'), the method calculates the corresponding fractional value and updates theresultaccordingly. It multiplies the difference betweenchand'0'byfractionand adds it to theresult. It then dividesfractionby 10 to handle the next digit and incrementsito move to the next character. -
If the character
chis'e', the method returns the result of another method calledparseExponent(which is not defined in the given code snippet). -
If the character
chis neither a digit nor'e', the method throws anUnexpectedCharacterExceptionwith an appropriate error message. -
After each iteration of the loop,
iis incremented to process the next character. -
Once the loop completes, the method returns the final
result.
Note: The given code snippet only includes the implementation of the parseFractionPart method. It is assumed that the parseExponent method is defined elsewhere in the code.

private static float parseExponent(int i, int endIndex, char[] chars, float result) {
boolean exponentNegative = false;
int exponent = 0;
char sign = chars[i];
switch(sign) {
case '-':
exponentNegative = true;
i++;
break;
case '+':
i++;
break;
}
while (i < endIndex) {
char ch = chars[i];
switch(chars[i]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
exponent = exponent * 10 + (ch - '0');
i++;
break;
default:
throw new UnexpectedCharacterException("float parsing exponent part", "Illegal character", ch, i);
}
}
if (exponentNegative) {
exponent = -exponent;
}
// Use Lookup table for powers of 10
// Calculate the power of 10
if (!exponentNegative) {
while (exponent >= powersOf10.length) {
result *= 1e18f;
exponent -= 18;
}
result *= powersOf10[exponent];
} else {
while (-exponent >= powersOf10.length) {
result /= 1e18f;
exponent += 18;
}
result /= powersOf10[-exponent];
}
return result;
}The method parseExponent is used to parse the exponent part of a floating-point number. Here is a step-by-step description of what the method is doing based on its body:
-
It accepts four parameters:
i(the starting index of the exponent part),endIndex(the ending index of the exponent part),chars(the array of characters representing the number), andresult(the current result of parsing the float value). -
It initializes a boolean variable
exponentNegativeto false, which will indicate if the exponent is negative. -
It initializes an integer variable
exponentto store the parsed exponent value. -
It retrieves the character at the index
ifrom thecharsarray and assigns it to the variablesign. -
It checks the value of
signusing a switch statement:- If
signis '-' (indicating a negative exponent), it setsexponentNegativeto true and incrementsiby 1. - If
signis '+' (indicating a positive exponent), it incrementsiby 1.
- If
-
It enters a while loop that iterates while the index
iis less thanendIndex. -
Inside the loop, it retrieves the character at the index
ifrom thecharsarray and assigns it to the variablech. -
It checks the value of
chusing a switch statement:- If
chis a digit from '0' to '9', it converts the character to its corresponding integer value and adds it to theexponentvariable. It then incrementsiby 1. - If
chis not a digit, it throws anUnexpectedCharacterExceptionwith an appropriate error message indicating that an illegal character was encountered during parsing.
- If
-
After the loop, it checks if
exponentNegativeis true. If so, it negates the value ofexponent. -
It enters an if-else condition to calculate the power of 10 based on the value of
exponentand update theresultaccordingly:- If
exponentNegativeis false (indicating a positive exponent), it enters a while loop that continues whileexponentis greater than or equal topowersOf10.length. Inside the loop, it multipliesresultby 1e18f (a constant representing 10^18) and subtracts 18 fromexponent. Finally, it multipliesresultby the power of 10 stored in thepowersOf10array at the indexexponent. - If
exponentNegativeis true (indicating a negative exponent), it enters a while loop that continues while the negative value ofexponentis greater than or equal topowersOf10.length. Inside the loop, it dividesresultby 1e18f and adds 18 to the negativeexponent. Finally, it dividesresultby the power of 10 stored in thepowersOf10array at the index-exponent.
- If
-
Finally, it returns the updated
result.
Note: The method assumes the existence of a powersOf10 array, which is not defined in the given code snippet.

This class represents an exception that is thrown when an unexpected character is encountered during parsing. It is used in cases where an unexpected character is encountered while parsing a JSON string or CharSource. This exception can be thrown by the JsonParser class in the io.nats.jparse.parser package. For more information, refer to the CharSource class and the JsonParser class.
The PathException class is a runtime exception that is used to handle errors related to JSON paths. It is thrown when an unexpected condition is encountered while processing a path.
The ParseDouble class is a class that is used to parse and convert string representations of numbers into the double data type.
public static double parseDouble(char[] chars, int startIndex, int endIndex) {
boolean negative = false;
int i = startIndex;
double result = 0;
// Check for a negative sign
if (chars[i] == '-') {
negative = true;
i++;
}
loop: while (i < endIndex) {
char ch = chars[i];
switch(ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
result = result * 10 + (ch - '0');
i++;
break;
case '.':
result = parseFractionPart(i + 1, endIndex, chars, result);
break loop;
case 'E':
case 'e':
result = parseExponent(i + 1, endIndex, chars, result);
break loop;
default:
throw new UnexpectedCharacterException("parsing double", "Illegal character", ch, i);
}
}
if (negative) {
result = -result;
}
return result;
}The parseDouble method defined in the ParseDouble class in the io.nats.jparse.source.support package is used to parse a double value from a character array.
Here is a step-by-step description of what the method does based on its body:
- Initialize a boolean variable
negativetofalse. - Initialize an integer variable
ito thestartIndexparameter. - Initialize a double variable
resultto0. - Check if the character at index
iin thecharsarray is a negative sign ('-'). If it is, setnegativetotrueand incrementiby 1. - Enter a loop that iterates while
iis less thanendIndex. - Get the character at index
iin thecharsarray and assign it to the variablech. - Use a switch statement to check the value of
ch:- If
chis a digit ('0' to '9'), multiplyresultby 10 and add the numerical value ofch(obtained by subtracting the character '0') to it. Then, incrementiby 1. - If
chis a period ('.'), call theparseFractionPartmethod with the parametersi + 1,endIndex,chars, andresult. Assign the returned value toresult, and break the loop using thebreak loopstatement. - If
chis an 'E' or 'e', call theparseExponentmethod with the parametersi + 1,endIndex,chars, andresult. Assign the returned value toresult, and break the loop using thebreak loopstatement. - If
chis none of the above, throw anUnexpectedCharacterExceptionwith the appropriate message, character, and position.
- If
- If
negativeistrue, negateresult. - Return the value of
result.
private static double parseFractionPart(int i, int endIndex, char[] chars, double result) {
double fraction = 0.1;
while (i < endIndex) {
char ch = chars[i];
switch(ch) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
result += (ch - '0') * fraction;
fraction /= 10;
i++;
break;
case 'E':
case 'e':
return parseExponent(i + 1, endIndex, chars, result);
default:
throw new UnexpectedCharacterException("double parsing fraction part", "Illegal character", ch, i);
}
}
return result;
}Class: io.nats.jparse.source.support.ParseDouble
Description: This method is used to parse the fraction part of a double number represented as a character array. It iterates through each character in the fraction part, calculates the numeric value of the fraction, and updates the overall result.
Parameters:
-
i(int): The current index of the character being processed in the fraction part. -
endIndex(int): The index of the last character in the fraction part. -
chars(char[]): The character array containing the fraction part of the double number. -
result(double): The accumulated result of parsing the fraction part.
Returns:
-
double: The final result after parsing the fraction part.
Steps:
- Initialize the fraction variable to 0.1.
- Start a while loop with the condition i < endIndex.
- Fetch the character at the current index from the character array and store it in the variable ch.
- Use a switch statement to perform actions based on the value of ch:
- If ch is a digit (0-9), perform the following steps:
- Convert the character to its numeric value by subtracting '0' from it.
- Multiply the numeric value by the fraction variable.
- Add the result to the updated numeric value.
- Divide the fraction variable by 10 to decrease its value.
- Increment i by 1 to move to the next character.
- Break out of the switch statement.
- If ch is 'E' or 'e', return the result of calling the parseExponent method with the appropriate parameters.
- If ch is neither a digit nor 'E' or 'e', throw an UnexpectedCharacterException with an appropriate error message.
- If ch is a digit (0-9), perform the following steps:
- After the while loop ends, return the final result.
Please let me know if you need more information.

private static double parseExponent(int i, int endIndex, char[] chars, double result) {
boolean exponentNegative = false;
int exponent = 0;
char sign = chars[i];
switch(sign) {
case '-':
exponentNegative = true;
i++;
break;
case '+':
i++;
break;
}
while (i < endIndex) {
char ch = chars[i];
switch(chars[i]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
exponent = exponent * 10 + (ch - '0');
i++;
break;
default:
throw new UnexpectedCharacterException("double parsing parsing exponent", "Illegal character", ch, i);
}
}
if (exponentNegative) {
exponent = -exponent;
}
// Use Lookup table for powers of 10
// Calculate the power of 10
if (!exponentNegative) {
while (exponent >= powersOf10.length) {
result *= 1e22;
exponent -= 22;
}
result *= powersOf10[exponent];
} else {
while (-exponent >= powersOf10.length) {
result /= 1e22;
exponent += 22;
}
result /= powersOf10[-exponent];
}
return result;
}The parseExponent method in class io.nats.jparse.source.support.ParseDouble is used to parse the exponent part of a floating-point number represented as a char array.
Here is a step-by-step description of what the method does:
-
The method takes in four parameters:
i(the current index of thechararray),endIndex(the index of the last character in thechararray),chars(thechararray containing the number), andresult(the parsed value of the number so far). -
The method initializes a boolean variable
exponentNegativetofalseand an integer variableexponentto0. It also stores the value of thei-th character in thecharsarray in a variablesign. -
The method then enters a switch statement based on the value of
sign: a. Ifsignis'-', theexponentNegativevariable is set totrueand the value ofiis incremented. b. Ifsignis'+', the value ofiis incremented. -
The method then enters a while loop that continues as long as
iis less thanendIndex. -
Inside the loop, the method retrieves the character at the
i-th index of thecharsarray and enters a switch statement based on its value. a. If the character is a digit (0-9), the value ofexponentis updated by multiplying it by 10 and adding the difference between the character value and the character value of '0'. The value ofiis also incremented. b. If the character is not a digit, anUnexpectedCharacterExceptionis thrown with an appropriate error message. -
After the while loop, the method checks if
exponentNegativeistrue. If it is, the value ofexponentis negated. -
The method then enters an
ifstatement to handle the calculation of the power of 10. a. IfexponentNegativeisfalse, a while loop is initiated that runs as long asexponentis greater than or equal to the length ofpowersOf10(presumably an array storing pre-calculated powers of 10).- Inside the loop,
resultis multiplied by 1e22 (which is 10 raised to the power 22) andexponentis decreased by 22. b. Finally,resultis multiplied by the power of 10 corresponding toexponent.
- Inside the loop,
-
If
exponentNegativeistrue, a similar while loop is initiated but with negatedexponentand division instead of multiplication. -
Finally, the method returns the
result.
Note: The code snippet provided doesn't include the definition of the powersOf10 array, so it's assumed that it's defined somewhere else in the code.

The CharArraySegment class is a public class that implements the CharSequence interface. It represents a segment of a character array (char[]), and provides access to a subsequence of the array as a CharSequence.

The PathNode class is a representation of a node in the parsed path of a structured data source, such as JSON or XML. It is a subclass of AbstractList and implements the CollectionNode interface.
public List<List> childrenTokens()
@Override
public List<List<Token>> childrenTokens() {
if (childrenTokens == null) {
childrenTokens = Arrays.stream(tokens.toArray()).map(Collections::singletonList).collect(Collectors.toList());
}
return childrenTokens;
}The childrenTokens method in the PathNode class is responsible for returning a list of token lists. Here is a step-by-step description of what this method is doing:
-
The method overrides the
childrenTokensmethod from the superclass, indicating that it provides a custom implementation for this method. -
The method checks if the
childrenTokensvariable is null. This variable is an instance variable of thePathNodeclass. -
If the
childrenTokensvariable is indeed null, the method proceeds to the next step. Otherwise, it directly returns thechildrenTokensvariable. -
Within the if block, the method creates a stream from the
tokenslist using theArrays.streammethod. Thetokenslist is an instance variable of thePathNodeclass. -
The stream of tokens is then mapped to a list of single-element lists using the
mapmethod. Each token is wrapped in a singleton list using theCollections::singletonListmethod reference. -
The resulting mapped stream is collected into a list of token lists using the
collectmethod. TheCollectors.toList()method is used to collect the elements into a List. -
The
childrenTokensvariable is assigned the newly created list of token lists. -
Finally, the method returns the
childrenTokensvariable.
In summary, the childrenTokens method returns a list of token lists. If the childrenTokens variable is null, it creates a new list by wrapping each token in the tokens list in a singleton list. This list is then assigned to the childrenTokens variable and returned. If the childrenTokens variable is not null, it is directly returned.
The childrenTokens method in the io.nats.jparse.path.PathNode class is overridden to return a list of token lists.
Within the method, it first checks if the childrenTokens variable is null. If it is null, it performs the following logic: it converts the array of tokens to a stream, maps each token to a singleton list using the Collections::singletonList method, and finally collects the singleton lists into a list using the Collectors.toList method.
Once the childrenTokens list is created, it is stored in the childrenTokens variable for future use. Finally, the method returns the childrenTokens list.
In summary, the childrenTokens method returns a list of token lists, where each token list represents a child of the PathNode.

Node[] elements() {
if (elements == null) {
elements = new Node[tokens.size()];
}
return elements;
}The elements method defined in the class io.nats.jparse.path.PathNode returns an array of Node objects.
Here is a step-by-step description of what this method is doing based on its body:
-
Check if the variable
elementsis null. -
If
elementsis null, it means that the array has not been initialized yet. -
In this case, we create a new array of
Nodeobjects with a size equal to the number of elements in thetokenslist. -
Assign the newly created array to the
elementsvariable. -
Finally, return the
elementsarray.
Essentially, this method ensures that the elements array is initialized and properly sized before returning it. If the array is already initialized, the method simply returns the existing array without any modification.
The method elements() in the io.nats.jparse.path.PathNode class is used to retrieve an array of Node objects.
First, it checks if the elements array is null. If it is null, it creates a new array with a size equal to the number of tokens. This is done to ensure that the elements array is initialized and has the same size as the list of tokens.
Finally, it returns the elements array, which may be either the newly created array or the already existing array.

public Iterator iterator()
@Override
public Iterator<PathElement> iterator() {
return new Iterator<PathElement>() {
int index = 0;
@Override
public boolean hasNext() {
return index < tokens().size();
}
@Override
public PathElement next() {
return (PathElement) getNodeAt(index++);
}
};
}The iterator() method in the class io.nats.jparse.path.PathNode returns an iterator for iterating over the PathElement objects in the tokens list.
Here is a step by step description of what the method is doing:
- The method defines an anonymous inner class that implements the
Iteratorinterface. - The inner class has a variable
indexinitialized to 0, which represents the current index in thetokenslist. - The
hasNext()method is overridden to check if theindexis less than the size of thetokenslist, indicating whether there are more elements to iterate over. - The
next()method is overridden to return thePathElementobject at the current index in thetokenslist using thegetNodeAt()method, and then increments theindexby 1. - The inner class is instantiated and returned as the iterator for the
PathNodeobject.
So, the iterator() method creates an iterator that allows iterating over the PathElement objects in the tokens list by implementing the hasNext() and next() methods.
The iterator method in the io.nats.jparse.path.PathNode class returns an iterator object that allows iterating over a collection of PathElement objects.
The implementation overrides the hasNext method to check if there are more elements in the collection to iterate through, and the next method returns the next PathElement object in the collection.
The iterator is implemented as an anonymous inner class that keeps track of the current index in the collection and returns the element at that index when next is called.

The PathParser class is a public class that implements the JsonParser interface. It provides similar functionality for parsing Json Paths as JSONPath expressions.
private List<Token> scan(CharSource source, TokenList tokens) {
char ch = ' ';
loop: while (true) {
ch = (char) source.next();
switch(ch) {
case ParseConstants.INDEX_BRACKET_START_TOKEN:
parseIndexOrKey(source, (char) source.next(), tokens);
break;
//'A';
case ParseConstants.A:
//'B';
case ParseConstants.B:
//'C';
case ParseConstants.C:
//'D';
case ParseConstants.D:
//'E';
case ParseConstants.E:
//'F';
case ParseConstants.F:
//'G';
case ParseConstants.G:
//'H';
case ParseConstants.H:
//'I';
case ParseConstants.I:
//'J';
case ParseConstants.J:
//'K';
case ParseConstants.K:
//'L';
case ParseConstants.L:
//'M';
case ParseConstants.M:
//'N';
case ParseConstants.N:
//'O';
case ParseConstants.O:
//'P';
case ParseConstants.P:
//'Q';
case ParseConstants.Q:
//'R';
case ParseConstants.R:
//'S';
case ParseConstants.S:
//'T';
case ParseConstants.T:
//'U';
case ParseConstants.U:
//'V';
case ParseConstants.V:
//'W';
case ParseConstants.W:
//'X';
case ParseConstants.X:
//'Y';
case ParseConstants.Y:
//'Z';
case ParseConstants.Z:
// = 'a';
case ParseConstants.A_:
//'b';
case ParseConstants.B_:
//'c';
case ParseConstants.C_:
//'d';
case ParseConstants.D_:
//'e';
case ParseConstants.E_:
//'f';
case ParseConstants.F_:
//'g';
case ParseConstants.G_:
//'h';
case ParseConstants.H_:
//'i';
case ParseConstants.I_:
//'j';
case ParseConstants.J_:
//'k';
case ParseConstants.K_:
//'l';
case ParseConstants.L_:
//'m';
case ParseConstants.M_:
//'n';
case ParseConstants.N_:
//'o';
case ParseConstants.O_:
//'p';
case ParseConstants.P_:
//'q';
case ParseConstants.Q_:
//'r';
case ParseConstants.R_:
//'s';
case ParseConstants.S_:
//'t';
case ParseConstants.T_:
//'u';
case ParseConstants.U_:
//'v';
case ParseConstants.V_:
//'w';
case ParseConstants.W_:
//'x';
case ParseConstants.X_:
//'y';
case ParseConstants.Y_:
case //'z';
ParseConstants.Z_:
parseKeyName(source, ch, tokens);
break;
case ParseConstants.DOT:
parseKeyName(source, (char) source.next(), tokens);
break;
case ParseConstants.ETX:
break loop;
default:
throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
}
}
return tokens;
}This method is defined in the class io.nats.jparse.path.PathParser.
The purpose of the scan method is to scan a CharSource and tokenize it, storing the tokens in a TokenList. The method performs a series of checks on each character in the input source and determines the appropriate action based on the character.
-
source(type:CharSource): The source containing the characters to be scanned. -
tokens(type:TokenList): The list to store the generated tokens.
- Initialize the variable
chwith a space character' '. - Enter an infinite loop labeled "loop".
- Inside the loop:
- Assign the next character from the
sourcetoch. - Start a switch statement based on the value of
ch.
- Case:
ParseConstants.INDEX_BRACKET_START_TOKEN- Call the method
parseIndexOrKeywith thesource, the next character fromsource, andtokensas arguments. - Break out of the switch statement.
- Call the method
- Cases:
ParseConstants.A,ParseConstants.B, ...,ParseConstants.Z,ParseConstants.A_,ParseConstants.B_, ...,ParseConstants.Z_- Call the method
parseKeyNamewith thesource,ch, andtokensas arguments. - Break out of the switch statement.
- Call the method
- Case:
ParseConstants.DOT- Call the method
parseKeyNamewith thesourceand the next character fromsourceas arguments. - Break out of the switch statement.
- Call the method
- Case:
ParseConstants.ETX- Break out of the loop labeled "loop".
- Default case:
- Throw an
IllegalStateExceptionwith a message indicating that the characterchcannot be understood with its index in the source.
- Throw an
- Assign the next character from the
- Return the
tokenslist.
Note: The method scans each character in the source one by one until it encounters an ETX character, which signifies the end of the input. During the scanning process, it performs specific actions based on the type of character encountered, such as parsing index, key, or throwing an exception for an unknown character.
The method scan in the class PathParser is used to scan the given source character by character and tokenize it based on certain conditions.
The method starts by initializing a loop that continues until it encounters a break statement. Inside the loop, it reads the next character from the source and assigns it to the variable ch.
Then, based on the value of ch, it performs different actions. If ch is equal to [ character, it calls the parseIndexOrKey method passing the next character from the source and the tokens list.
If ch is equal to any uppercase or lowercase letter (A to Z, a to z), it calls the parseKeyName method passing the source, ch, and tokens as arguments.
If ch is equal to . character, it calls the parseKeyName method passing the next character from the source and the tokens list.
If ch is equal to ETX character, it breaks the loop and the method returns the tokens list.
If ch does not match any of the above cases, it throws an IllegalStateException with an error message indicating the character ch and its index in the source.
private void parseIndexOrKey(CharSource source, char ch, TokenList tokens) {
final int startIndex = source.getIndex();
switch(ch) {
case ParseConstants.NUM_0:
case ParseConstants.NUM_1:
case ParseConstants.NUM_2:
case ParseConstants.NUM_3:
case ParseConstants.NUM_4:
case ParseConstants.NUM_5:
case ParseConstants.NUM_6:
case ParseConstants.NUM_7:
case ParseConstants.NUM_8:
case ParseConstants.NUM_9:
parseIndex(source, startIndex, tokens, ch);
break;
case ParseConstants.SINGLE_QUOTE:
parseKeyWithQuotes(source, startIndex + 1, tokens, ch);
break;
case ParseConstants.ETX:
throw new IllegalStateException("reached end");
default:
throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
}
}The parseIndexOrKey method is a private method defined in the PathParser class in the io.nats.jparse.path package. This method is responsible for parsing an index or a key from a given character source.
-
source: The character source from which to parse the index or key. -
ch: The current character being processed. -
tokens: The list of tokens where the parsed index or key will be added.
- Get the start index of the character source.
- Switch based on the value of
ch:- If
chis one of the constant valuesParseConstants.NUM_0,ParseConstants.NUM_1,ParseConstants.NUM_2,ParseConstants.NUM_3,ParseConstants.NUM_4,ParseConstants.NUM_5,ParseConstants.NUM_6,ParseConstants.NUM_7,ParseConstants.NUM_8,ParseConstants.NUM_9, then call theparseIndexmethod with thesource,startIndex,tokens, andchas parameters. - If
chis equal to the constant valueParseConstants.SINGLE_QUOTE, then call theparseKeyWithQuotesmethod with thesource,startIndex + 1,tokens, andchas parameters. - If
chis equal to the constant valueParseConstants.ETX, then throw anIllegalStateExceptionwith the message "reached end". - If none of the above conditions are met, then throw an
IllegalStateExceptionwith the message "Unable to understand char <ch> index <source.getIndex()>".
- If
This method does not have a return type.
The parseIndexOrKey method, defined in the class PathParser in the io.nats.jparse.path package, is responsible for parsing an index or key from a given CharSource and adding it to the provided TokenList.
The method takes three parameters: source, which represents the source of characters to parse; ch, which is the current character to be processed; and tokens, which is the list where the parsed index or key will be added.
Inside the method, it first determines the startIndex of the current CharSource. Then, based on the value of ch, it performs one of the following actions:
- If
chis a digit from 0 to 9, the method calls theparseIndexmethod passing thesource,startIndex,tokens, andchas parameters. This indicates that an index is being parsed. - If
chis a single quote ('), the method calls theparseKeyWithQuotesmethod passing thesource,startIndex + 1,tokens, andchas parameters. This indicates that a key enclosed in quotes is being parsed. - If
chis the end of text (ETX), the method throws anIllegalStateExceptionwith the message "reached end". This indicates that the end of the input has been reached unexpectedly. - If none of the above conditions are met, the method throws an
IllegalStateExceptionwith the message "Unable to understand char [ch] index [source.getIndex()]". This indicates that the provided character is not recognized and cannot be parsed.
In summary, the parseIndexOrKey method in the PathParser class parses either an index or a key from a given CharSource based on the provided character. Depending on the character value, it either calls parseIndex, parseKeyWithQuotes, or throws an exception if the character is not recognized.

private void parseKeyWithQuotes(CharSource source, int startIndex, TokenList tokens, char ch) {
loop: while (true) {
ch = (char) source.next();
switch(ch) {
//'A';
case ParseConstants.A:
//'B';
case ParseConstants.B:
//'C';
case ParseConstants.C:
//'D';
case ParseConstants.D:
//'E';
case ParseConstants.E:
//'F';
case ParseConstants.F:
//'G';
case ParseConstants.G:
//'H';
case ParseConstants.H:
//'I';
case ParseConstants.I:
//'J';
case ParseConstants.J:
//'K';
case ParseConstants.K:
//'L';
case ParseConstants.L:
//'M';
case ParseConstants.M:
//'N';
case ParseConstants.N:
//'O';
case ParseConstants.O:
//'P';
case ParseConstants.P:
//'Q';
case ParseConstants.Q:
//'R';
case ParseConstants.R:
//'S';
case ParseConstants.S:
//'T';
case ParseConstants.T:
//'U';
case ParseConstants.U:
//'V';
case ParseConstants.V:
//'W';
case ParseConstants.W:
//'X';
case ParseConstants.X:
//'Y';
case ParseConstants.Y:
//'Z';
case ParseConstants.Z:
// = 'a';
case ParseConstants.A_:
//'b';
case ParseConstants.B_:
//'c';
case ParseConstants.C_:
//'d';
case ParseConstants.D_:
//'e';
case ParseConstants.E_:
//'f';
case ParseConstants.F_:
//'g';
case ParseConstants.G_:
//'h';
case ParseConstants.H_:
//'i';
case ParseConstants.I_:
//'j';
case ParseConstants.J_:
//'k';
case ParseConstants.K_:
//'l';
case ParseConstants.L_:
//'m';
case ParseConstants.M_:
//'n';
case ParseConstants.N_:
//'o';
case ParseConstants.O_:
//'p';
case ParseConstants.P_:
//'q';
case ParseConstants.Q_:
//'r';
case ParseConstants.R_:
//'s';
case ParseConstants.S_:
//'t';
case ParseConstants.T_:
//'u';
case ParseConstants.U_:
//'v';
case ParseConstants.V_:
//'w';
case ParseConstants.W_:
//'x';
case ParseConstants.X_:
//'y';
case ParseConstants.Y_:
//'z';
case ParseConstants.Z_:
case ParseConstants.NEW_LINE_WS:
case ParseConstants.CARRIAGE_RETURN_WS:
case ParseConstants.TAB_WS:
case ParseConstants.SPACE_WS:
continue;
case ParseConstants.SINGLE_QUOTE:
break loop;
case ParseConstants.ETX:
throw new IllegalStateException("reached end");
default:
if (ch > 20 && ch < 127) {
break;
} else {
throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
}
}
}
final int endIndex = source.getIndex();
int i = source.nextSkipWhiteSpace();
if (i == ParseConstants.INDEX_BRACKET_END_TOKEN) {
tokens.add(new Token(startIndex, endIndex, TokenTypes.PATH_KEY_TOKEN));
} else {
throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
}
}The parseKeyWithQuotes method is defined in the io.nats.jparse.path.PathParser class. It is responsible for parsing a key with quotes from a given source of characters. Here is a step-by-step description of what the method does:
- The method takes four parameters:
source,startIndex,tokens, andch. - The method starts an infinite loop using a
whilestatement with the labelloop. - Inside the loop, it retrieves the next character from the
sourceusingsource.next()and assigns it toch. - It then checks the value of
chusing aswitchstatement. - If
chmatches any of the constants defined in theParseConstantsclass corresponding to characters from 'A' to 'Z', 'a' to 'z', or whitespace characters, it continues to the next iteration of the loop. - If
chmatches the constantParseConstants.SINGLE_QUOTE, it breaks out of the loop using thebreakstatement with the labelloop. - If
chmatches the constantParseConstants.ETX, it throws anIllegalStateExceptionwith the message "reached end". - If none of the above conditions match, it checks if
chis a printable ASCII character by comparing its value with the range of 20 to 127. If it is, it breaks out of the loop. Otherwise, it throws anIllegalStateExceptionwith the message "Unable to understand char " + ch + " index " + source.getIndex()". - After breaking out of the loop, it assigns the current index of the
sourceto the variableendIndex. - It then calls the
nextSkipWhiteSpace()method on thesourceto get the next non-whitespace character and assigns it to the variablei. - If
iequals the constantParseConstants.INDEX_BRACKET_END_TOKEN, it adds a newTokenobject to thetokenslist with thestartIndex,endIndex, andTokenTypes.PATH_KEY_TOKEN. - If
idoes not match the constantParseConstants.INDEX_BRACKET_END_TOKEN, it throws anIllegalStateExceptionwith the message "Unable to understand char " + ch + " index " + source.getIndex()".
Note: The exact behavior and purpose of the method may depend on the implementation details of the CharSource and TokenList classes, which are not provided in the given code snippet.
The parseKeyWithQuotes method in the PathParser class is responsible for parsing a key with quotes from a given character source. It iterates through the characters in the source and performs various checks and validations. If the character is a valid key character (including upper and lower case letters and the underscore), or a whitespace character, it continues to the next character. If the character is a single quote, it breaks out of the loop. If the character is the ETX (end of transmission) character, it throws an exception. If the character is not a valid key character or whitespace, it throws an exception indicating that it is unable to understand the character.
Finally, it retrieves the end index from the character source and checks the next character after skipping whitespace. If the next character is the closing bracket token, it adds a new token to the token list representing the parsed key. Otherwise, it throws an exception indicating that it is unable to understand the character.
private void parseKeyName(CharSource source, char ch, TokenList tokens) {
final int startIndex = source.getIndex();
loop: while (true) {
ch = (char) source.next();
switch(ch) {
//'A';
case ParseConstants.A:
//'B';
case ParseConstants.B:
//'C';
case ParseConstants.C:
//'D';
case ParseConstants.D:
//'E';
case ParseConstants.E:
//'F';
case ParseConstants.F:
//'G';
case ParseConstants.G:
//'H';
case ParseConstants.H:
//'I';
case ParseConstants.I:
//'J';
case ParseConstants.J:
//'K';
case ParseConstants.K:
//'L';
case ParseConstants.L:
//'M';
case ParseConstants.M:
//'N';
case ParseConstants.N:
//'O';
case ParseConstants.O:
//'P';
case ParseConstants.P:
//'Q';
case ParseConstants.Q:
//'R';
case ParseConstants.R:
//'S';
case ParseConstants.S:
//'T';
case ParseConstants.T:
//'U';
case ParseConstants.U:
//'V';
case ParseConstants.V:
//'W';
case ParseConstants.W:
//'X';
case ParseConstants.X:
//'Y';
case ParseConstants.Y:
//'Z';
case ParseConstants.Z:
// = 'a';
case ParseConstants.A_:
//'b';
case ParseConstants.B_:
//'c';
case ParseConstants.C_:
//'d';
case ParseConstants.D_:
//'e';
case ParseConstants.E_:
//'f';
case ParseConstants.F_:
//'g';
case ParseConstants.G_:
//'h';
case ParseConstants.H_:
//'i';
case ParseConstants.I_:
//'j';
case ParseConstants.J_:
//'k';
case ParseConstants.K_:
//'l';
case ParseConstants.L_:
//'m';
case ParseConstants.M_:
//'n';
case ParseConstants.N_:
//'o';
case ParseConstants.O_:
//'p';
case ParseConstants.P_:
//'q';
case ParseConstants.Q_:
//'r';
case ParseConstants.R_:
//'s';
case ParseConstants.S_:
//'t';
case ParseConstants.T_:
//'u';
case ParseConstants.U_:
//'v';
case ParseConstants.V_:
//'w';
case ParseConstants.W_:
//'x';
case ParseConstants.X_:
//'y';
case ParseConstants.Y_:
case //'z';
ParseConstants.Z_:
continue;
case ParseConstants.ETX:
break loop;
case ParseConstants.DOT:
break loop;
case ParseConstants.INDEX_BRACKET_START_TOKEN:
final int endIndex = source.getIndex();
tokens.add(new Token(startIndex, endIndex, TokenTypes.PATH_KEY_TOKEN));
parseIndexOrKey(source, (char) source.next(), tokens);
return;
default:
throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
}
}
final int endIndex = source.getIndex();
tokens.add(new Token(startIndex, endIndex, TokenTypes.PATH_KEY_TOKEN));
}The parseKeyName method in the PathParser class is responsible for parsing a key name from a character source. It follows these steps:
- Start a loop that continues indefinitely.
- Get the next character from the character source.
- Check the value of the character using a switch statement.
- If the character is one of the uppercase letters from 'A' to 'Z' or the lowercase letter 'a', 'b', 'c', ..., 'z', continue to the next iteration of the loop.
- If the character is the end-of-text character (represented by
ParseConstants.ETX) or a dot character (represented byParseConstants.DOT), break out of the loop. - If the character is an opening square bracket (represented by
ParseConstants.INDEX_BRACKET_START_TOKEN), create a token for the current key name, add it to the token list, and call theparseIndexOrKeymethod to parse the index or key that follows the square bracket. - Return from the method.
- If none of the above cases match, throw an
IllegalStateExceptionwith an error message indicating that the character is not recognized. - After breaking out of the loop, create a token for the current key name, add it to the token list, and return from the method.
The parseKeyName method is responsible for parsing a key name from a given source of characters. It iterates over the characters in the source and checks each character against a set of predefined constants representing valid key name characters. If the character is a valid key name character, the iteration continues. If the character is a delimiter, like a dot or an index bracket start token, the method adds a token representing the key name to a list of tokens and calls another method to parse the index or key following the delimiter. If the character is neither a valid key name character nor a delimiter, an exception is thrown indicating that the character is not understood. Once the iteration is complete, the method adds a final key name token to the list and returns.

private void parseIndex(CharSource source, int startIndex, TokenList tokens, char ch) {
loop: while (true) {
ch = (char) source.next();
switch(ch) {
case ParseConstants.NUM_0:
case ParseConstants.NUM_1:
case ParseConstants.NUM_2:
case ParseConstants.NUM_3:
case ParseConstants.NUM_4:
case ParseConstants.NUM_5:
case ParseConstants.NUM_6:
case ParseConstants.NUM_7:
case ParseConstants.NUM_8:
case ParseConstants.NUM_9:
break;
case ParseConstants.INDEX_BRACKET_END_TOKEN:
break loop;
case ParseConstants.ETX:
throw new IllegalStateException("reached end");
default:
throw new IllegalStateException("Unable to understand char " + ch + " index " + source.getIndex());
}
}
final int endIndex = source.getIndex();
tokens.add(new Token(startIndex, endIndex, TokenTypes.PATH_INDEX_TOKEN));
}This method is defined in the io.nats.jparse.path.PathParser class and is used to parse an index from a CharSource object.
-
The method starts by entering an infinite loop using a
while (true)statement. This loop will break only when a specific condition is met. -
Inside the loop, the next character from the
CharSourceobject is retrieved using thesource.next()method and assigned to the variablech. -
A switch statement is used to check the value of
chand perform different actions based on its value. The following cases are handled:-
If
chis'0','1','2','3','4','5','6','7','8', or'9', no action is taken. -
If
chis']', the loop is broken using thebreak loop;statement. -
If
chisParseConstants.ETX, anIllegalStateExceptionis thrown with the message "reached end". -
If none of the above cases match, an
IllegalStateExceptionis thrown with the message "Unable to understand char " + ch + " index " + source.getIndex()".
-
-
After the loop is exited, the final index of the
CharSourceobject is retrieved using thesource.getIndex()method and assigned to the variableendIndex. -
A new
Tokenobject is created with thestartIndex,endIndex, andTokenTypes.PATH_INDEX_TOKEN. This token is then added to thetokenslist using thetokens.add()method.
Note: The TokenList and Token objects mentioned here are assumed to be defined elsewhere and are not shown in the given code snippet.
The parseIndex method in the io.nats.jparse.path.PathParser class is used to parse an index from a character source (CharSource).
The method iterates through the characters in the source until it reaches a specific condition. It checks if each character is a digit from 0 to 9 and if so, continues to the next character. If the character is the end token for an index bracket, it breaks out of the loop. If the character is the ETX (end of text) constant, it throws an IllegalStateException with the message "reached end". If none of these conditions are met, it throws an IllegalStateException with the message "Unable to understand char [char] index [index]".
Once the loop is broken, the method retrieves the current index from the source and adds a new token to the tokens list. This token represents the parsed index and is defined by the TOKEN_INDEX constant.
Overall, the parseIndex method is responsible for parsing an index from a character source and adding it as a token to a list.

The KeyPathNode class is a public class that represents a key element of a JSON Path expression. It implements the ScalarNode and PathElement interfaces. It provides methods for determining the type of element and for converting it to a key representation.
The IndexPathNode class is a public class that represents an index element of a JSON Path expression. It is a node in the parse tree that implements the ScalarNode, CharSequence, and PathElement interfaces.
/**
- Returns the value of this node as an int.
- @return The int value represented by this object. */ @Override public int intValue()
// Overridden Number class methods with their appropriate Javadoc comments
/**
* Returns the value of this node as an int.
*
* @return The int value represented by this object.
*/
@Override
public int intValue() {
return source.getInt(token.startIndex, token.endIndex);
}The intValue method, which is defined in the io.nats.jparse.path.IndexPathNode class, is responsible for returning the value of the node as an int. Here is a step-by-step description of what the method is doing based on its body:
-
The method is overridden with appropriate Javadoc comments to explain its functionality.
-
The method signature specifies that the return type is
int. -
Inside the method body, a call to the
source.getInt()method is made, passing two parameters:token.startIndexandtoken.endIndex. This indicates that thesourceobject has a method calledgetInt()that accepts the start and end indexes of the token. -
The return value of the
source.getInt()method is used as the return value of theintValue()method.
Overall, the intValue() method is retrieving the int value from the source object by passing the start and end indexes of the token and returning that value as the result of the method call.
The intValue method in the IndexPathNode class, located in the io.nats.jparse.path package, returns the value of this node as an integer. It retrieves the integer value from the source object, using the start and end indices of the token associated with this node.


The JsonTestUtils class is a public class that provides utilities for testing JSON data in software engineering. It provides convenient methods for comparing and validating JSON objects, making it easier to write test cases for code that deals with JSON data.
The NullNode class represents a null value node in a tree structure. It is a concrete implementation of the ScalarNode interface.
public char charAt(int index)
@Override
public char charAt(int index) {
switch(index) {
case 0:
return 'n';
case 1:
return 'u';
case 2:
case 3:
return 'l';
default:
throw new IllegalStateException();
}
}This method is part of the NullNode class in the io.nats.jparse.node package. It is an overridden implementation of the charAt method from the CharSequence interface.
The charAt method returns the character at the specified index of the NullNode object.
-
index(integer): The index of the character to retrieve.
-
char: The character at the specified index.
- Start the method execution.
- Check the value of the
indexparameter using aswitchstatement. - If
indexis 0, return the character'n'. - If
indexis 1, return the character'u'. - If
indexis 2 or 3, return the character'l'. - If none of the above cases match, throw an
IllegalStateException. - End the method execution.
Note: This method only handles the cases 0, 1, 2, 3. Any other value will result in an exception being thrown.

The NumberNode class represents a numeric node in a tree structure. It can store integer, long, float, and double values. This class implements the ScalarNode and CharSequence interfaces.
public Object value()
@Override
public Object value() {
if (isInteger()) {
return intValue();
} else if (isLong()) {
return longValue();
} else {
return this.doubleValue();
}
}The method value() in the class io.nats.jparse.node.NumberNode returns the value of the number node. Here is a step-by-step description of what this method does based on its body:
- Check if the number node is an integer, by calling the method
isInteger(). - If the number node is an integer, call the method
intValue()to get the integer value and return it as anObject. - If the number node is not an integer, check if it is a long integer, by calling the method
isLong(). - If the number node is a long integer, call the method
longValue()to get the long integer value and return it as anObject. - If the number node is neither an integer nor a long integer, call the method
doubleValue()to get the double value and return it as anObject.
The purpose of this method is to provide a consistent way of accessing the value of a number node, regardless of its specific data type (integer, long, or double).

public char charAt(int index)
@Override
public char charAt(int index) {
if (index > length()) {
throw new ArrayIndexOutOfBoundsException(index);
}
return source.getChartAt(token.startIndex + index);
}The charAt method in the NumberNode class is designed to retrieve the character at a specified index in the source string. Here is a step-by-step description of what the method does:
-
The method overrides the
charAtmethod defined in theCharSequenceinterface. -
It takes an
intparameter calledindex, which represents the desired index of the character to be retrieved. -
The method first checks if the
indexis greater than the length of thesourcestring. -
If the
indexis greater than the length of thesourcestring, the method throws anArrayIndexOutOfBoundsExceptionwith the providedindex. -
If the
indexis valid (i.e., within the bounds of thesourcestring), the method retrieves the character at the specified index. -
The character is obtained by calling the
getChartAtmethod on thesourceobject, passing thestartIndexof thetokenplus theindexas arguments. -
Finally, the retrieved character is returned as the result of the method.
In summary, the charAt method in the NumberNode class ensures that the specified index is valid, and then retrieves and returns the character at that index from the source string.

public CharSequence subSequence(int start, int end)
@Override
public CharSequence subSequence(int start, int end) {
if (end > length()) {
throw new IndexOutOfBoundsException();
}
return source.getCharSequence(start + token.startIndex, end + token.startIndex);
}The subSequence method, which is defined in the NumberNode class in the io.nats.jparse.node package, allows us to get a portion of the character sequence contained in the NumberNode object.
Here is a step-by-step description of what the method does based on its body:
-
The method is annotated with
@Override, indicating that it overrides a method from the superclass or an interface. In this case, it overrides thesubSequencemethod from theCharSequenceinterface. -
The method has two input parameters,
startandend, which indicate the range of indices (inclusive) for the desired subsequence. -
The first line of the method's body checks if the
endparameter is greater than the length of the character sequence. If it is, anIndexOutOfBoundsExceptionis thrown. -
If the
endparameter is within the valid range, the method proceeds to the next line. -
The method then calls the
getCharSequencemethod on thesourceobject with the calculated start and end indices. Thestartindex is obtained by adding thestartparameter to thestartIndexof thetokenobject, and theendindex is obtained by adding theendparameter to thestartIndexof thetokenobject. -
Finally, the
getCharSequencemethod returns the requested subsequence of characters.
That's the step-by-step description of the subSequence method in the NumberNode class.

public boolean isInteger() {
switch(elementType) {
case INT:
return source.isInteger(this.token.startIndex, this.token.endIndex);
default:
return false;
}
}The method isInteger() located in the io.nats.jparse.node.NumberNode class is used to determine if the given number is an integer. Here is a step-by-step description of how this method works based on its implementation:
-
The method
isInteger()takes no parameters and returns a boolean value indicating whether the number is an integer or not. -
The method starts by checking the value of the
elementTypevariable, which is an enumeration representing the type of the number. -
If the
elementTypeisINT, it means that the number is an integer. -
In the case when the
elementTypeisINT, theisInteger()method calls thesource.isInteger()method passing two parametersthis.token.startIndexandthis.token.endIndex. These parameters represent the start and end indices of the token associated with this number. -
The
source.isInteger()method is expected to be implemented in another class and is responsible for determining if the number between the given indices is an integer or not. -
If the
elementTypeis notINT, the method returnsfalse, indicating that the number is not an integer. -
The
isInteger()method provides a way to validate if the given number is an integer based on its typeelementType.

public boolean isLong() {
switch(elementType) {
case INT:
return !source.isInteger(this.token.startIndex, this.token.endIndex);
default:
return false;
}
}The method isLong() in the NumberNode class, located in the io.nats.jparse.node package, is used to determine whether the number represented by the node is a long type or not. Below is a step-by-step description of how this method works based on its body:
-
The method is defined as a
publicboolean method, meaning it returns a boolean value and can be accessed from outside the class. -
The method starts with a
switchstatement that evaluates the value of theelementTypevariable. TheelementTypevariable is presumably an enumeration or constant that represents the type of the element. -
Inside the
switchstatement, there is acasefor theINTtype. This means that if theelementTypeis equal toINT, the following code will be executed. -
Within the
case INT, there is a return statement that calls a methodisInteger()on thesourceobject. This method is likely defined in another class or utility and takes two parameters:this.token.startIndexandthis.token.endIndex. The purpose of this method is to check whether the token, which represents a portion of the input source, is an integer. -
The
!operator is applied to the result of theisInteger()method. This means that if the token is NOT an integer, the result will betrue, indicating that the number is a long type. -
If the
elementTypeis not equal toINT, thedefaultcase is executed. In this case, the method returnsfalse, indicating that the number is not a long type.
To summarize, the isLong() method checks the elementType of the node and if it is an INT, it verifies whether the corresponding token represents an integer. If the token is not an integer, the method returns true, indicating that the number is a long type. Otherwise, if the elementType is not INT, the method returns false.

The StringNode class in the JParse library is a specialized ScalarNode that represents a string value. It contains information about the token, source, start and end indices, and whether the string should be encoded by default. This class provides methods to access the string value, perform operations on the string such as getting the length and retrieving characters, and creating substrings. StringNode implements the CharSequence interface and overrides the equals and hashCode methods for proper comparison and hashing of the string value.
For more information, see the documentation for the related classes: ScalarNode (from the io.nats.jparse.node package) and CharSequence (from the java.lang package).
The RootNode class is a concrete implementation of the CollectionNode interface. It represents the root node of a tree structure. This class serves as the entry point for accessing and manipulating the contents of the tree. The root node can be either an object node or an array node.
public List<List> childrenTokens()
@Override
public List<List<Token>> childrenTokens() {
switch(rootToken.type) {
case OBJECT_TOKEN:
return getObjectNode().childrenTokens();
case ARRAY_TOKEN:
return getArrayNode().childrenTokens();
default:
return doGetChildrenTokens();
}
}The childrenTokens() method in the io.nats.jparse.node.RootNode class is defined as follows:
-
The method is annotated with
@Override, indicating that it overrides a method from a superclass or interface. -
The method returns a
List<List<Token>>, which is a list of lists ofTokenobjects. -
The method utilizes a
switchstatement based on thetypeof therootTokenvariable. -
If the
typeofrootTokenisOBJECT_TOKEN, the method calls thechildrenTokens()method on theObjectNodeinstance returned by thegetObjectNode()method. The returnedList<List<Token>>is then returned by the method. -
If the
typeofrootTokenisARRAY_TOKEN, the method calls thechildrenTokens()method on theArrayNodeinstance returned by thegetArrayNode()method. The returnedList<List<Token>>is then returned by the method. -
If the
typeofrootTokendoes not match any of the above cases, the method calls thedoGetChildrenTokens()method. This method is not explicitly provided in the given snippet, but it is assumed to return aList<List<Token>>. The returned value is then returned by thechildrenTokens()method.
Note: Without the implementation of the getObjectNode(), getArrayNode(), and doGetChildrenTokens() methods, it is not possible to provide a more detailed description of their functionality and behavior.

The ObjectNode class represents an object node in a tree structure.
It extends the AbstractMap class and implements the CollectionNode interface.
Object nodes are used to store key-value pairs, where the keys are CharSequences and the values are nodes in the tree structure.
public List<List> childrenTokens()
@Override
public List<List<Token>> childrenTokens() {
if (childrenTokens == null) {
childrenTokens = NodeUtils.getChildrenTokens(tokens);
}
return childrenTokens;
}The method childrenTokens() in the ObjectNode class is used to retrieve the children tokens of the current object node. Here is a step-by-step description of what this method does:
-
The method is annotated with
@Override, indicating that it overrides the implementation of the same method in a superclass or interface. -
The return type of the method is
List<List<Token>>, which means it returns a list of lists ofTokenobjects. -
Inside the method, there is an if statement to check if the
childrenTokensvariable isnull. This variable is an instance variable of theObjectNodeclass. -
If
childrenTokensisnull, the method proceeds to the next line. Otherwise, it skips to the return statement. -
On the next line, the method calls the
getChildrenTokens()method from theNodeUtilsclass and passes thetokensparameter to it. Thetokensparameter is an instance variable of theObjectNodeclass. -
The return value from the
getChildrenTokens()method is assigned to thechildrenTokensvariable. -
Finally, the method returns the value of the
childrenTokensvariable.
In summary, the childrenTokens() method is used to retrieve the children tokens of the current object node. It first checks if the childrenTokens variable is null. If it is null, it calls a helper method to fetch the children tokens and assigns the result to the childrenTokens variable. Then, it returns the value of the childrenTokens variable.

public Set<Entry<CharSequence, Node>> entrySet()
@Override
public Set<Entry<CharSequence, Node>> entrySet() {
return new AbstractSet<Entry<CharSequence, Node>>() {
/**
* Checks if the object node contains the specified entry.
*
* @param o the entry to check for existence
* @return {@code true} if the object node contains the entry, {@code false} otherwise
*/
@Override
public boolean contains(Object o) {
return keys().contains(o);
}
/**
* Returns an iterator over the entries in the object node.
*
* @return an iterator over the entries in the object node
*/
@Override
public Iterator<Entry<CharSequence, Node>> iterator() {
final Iterator<CharSequence> iterator = keys().iterator();
return new Iterator<Entry<CharSequence, Node>>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public Entry<CharSequence, Node> next() {
final CharSequence nextKey = iterator.next().toString();
return new Entry<CharSequence, Node>() {
@Override
public CharSequence getKey() {
return nextKey;
}
@Override
public Node getValue() {
return lookupElement(nextKey);
}
@Override
public Node setValue(Node value) {
throw new UnsupportedOperationException();
}
};
}
};
}
/**
* Returns the number of entries in the object node.
*
* @return the number of entries in the object node
*/
@Override
public int size() {
return keys().size();
}
};
}The entrySet method is defined in class io.nats.jparse.node.ObjectNode and is overridden from its superclass. Here is a step-by-step description of what this method is doing:
-
The
entrySetmethod is marked with the@Overrideannotation, indicating that it is overriding a method from the superclass. -
The method returns a new instance of
AbstractSet<Entry<CharSequence, Node>>. This means that it returns a set of map entries, where each entry consists of aCharSequencekey and aNodevalue. -
Inside the
AbstractSetconstructor, several methods are overridden and implemented. These methods provide functionality for checking if the object node contains a specific entry, iterating over the entries, and getting the size of the entry set. -
The
containsmethod takes an object as a parameter and checks if the object node contains the specified entry. It delegates the check to thekeysmethod, which returns a set of keys in the object node, and then calls thecontainsmethod of that set. -
The
iteratormethod returns an iterator over the entries in the object node. It first obtains an iterator over the keys in the object node by calling thekeysmethod. Then, it returns a new iterator object that implements theIterator<Entry<CharSequence, Node>>interface. Each iteration, it converts the next key into aCharSequenceand creates a new entry object with the key and the value obtained by calling thelookupElementmethod. -
The
sizemethod returns the number of entries in the object node. It delegates the size calculation to thekeysmethod, which returns a set of keys in the object node, and then calls thesizemethod of that set.
Overall, the entrySet method provides a way to work with the entries of the object node as a set, allowing operations such as checking if an entry exists, iterating over the entries, and getting the size of the entry set.

private Node lookupElement(final CharSequence key) {
if (elementMap == null) {
elementMap = new HashMap<>();
}
Node node = elementMap.get(key);
if (node == null) {
List<List<Token>> childrenTokens = childrenTokens();
for (int index = 0; index < childrenTokens.size(); index += 2) {
List<Token> itemKey = childrenTokens.get(index);
if (doesMatchKey(itemKey, key)) {
node = NodeUtils.createNodeForObject(childrenTokens.get(index + 1), source, objectsKeysCanBeEncoded);
elementMap.put(key, node);
break;
}
}
}
return node;
}The lookupElement method is defined in the ObjectNode class and is used to look up an element based on a given key.
private Node lookupElement(final CharSequence key)-
Check if the
elementMapattribute is null.- If it is null, create a new
HashMapand assign it toelementMap.
- If it is null, create a new
-
Retrieve the node associated with the given key from the
elementMap.- Store the result in the
nodevariable.
- Store the result in the
-
Check if the retrieved node is null.
- If it is null, proceed with the following steps.
- If it is not null, skip the following steps and return the node.
-
Retrieve the
childrenTokensby calling thechildrenTokens()method. -
Iterate over the
childrenTokenslist in increments of 2.- For each pair of tokens (item key and value):
- Store the item key in the
itemKeyvariable.
- Store the item key in the
- For each pair of tokens (item key and value):
-
Check if the item key matches the given key by calling the
doesMatchKeymethod.- If it matches, proceed with the following steps.
- If it does not match, move to the next pair of tokens.
-
Call the
createNodeForObjectmethod from theNodeUtilsclass, passing the value tokens, source, andobjectsKeysCanBeEncodedarguments.- Store the returned node in the
nodevariable.
- Store the returned node in the
-
Add the key and node pair to the
elementMap.- This stores the key-value mapping for future lookups.
-
Exit the loop.
-
Return the node.
The method returns the node associated with the given key.

private boolean doesMatchKey(final List<Token> itemKey, final CharSequence key) {
final Token keyToken = itemKey.get(1);
if (keyToken.type == TokenTypes.STRING_TOKEN) {
if (keyToken.length() != key.length()) {
return false;
}
if (objectsKeysCanBeEncoded) {
final StringNode stringNode = new StringNode(keyToken, source, objectsKeysCanBeEncoded);
final String string = stringNode.toString();
for (int index = 0; index < key.length(); index++) {
if (string.charAt(index) != key.charAt(index)) {
return false;
}
}
return true;
} else {
return source.matchChars(keyToken.startIndex, keyToken.endIndex, key);
}
}
return false;
}The doesMatchKey method is a private method defined in the io.nats.jparse.node.ObjectNode class. This method is used to check whether a given key matches a specified item key.
-
itemKey(Type:List<Token>): A list of tokens representing the item key. -
key(Type:CharSequence): The key to be checked for a match.
- Get the token at index 1 from the
itemKeylist, and assign it to thekeyTokenvariable. - Check the type of the
keyToken:- If the type is
TokenTypes.STRING_TOKEN, proceed with the following steps:- Check if the length of
keyTokenis equal to the length of thekey:- If not equal, return
false.
- If not equal, return
- Check if
objectsKeysCanBeEncodedistrue:- If
true, execute the following sub-steps:- Create a new
StringNodeobject namedstringNodewith thekeyToken,source, andobjectsKeysCanBeEncodedas parameters. - Convert the
stringNodeto aStringand assign it to thestringvariable. - Iterate over each character in the
keyusing a for loop:- Compare the character at the current index in the
stringwith the character at the current index in thekey:- If they are not equal, return
false.
- If they are not equal, return
- Compare the character at the current index in the
- If all characters match, return
true.
- Create a new
- If
false, execute the following sub-step:- Call the
matchCharsmethod on thesourceobject, passingkeyToken.startIndex,keyToken.endIndex, andkeyas parameters. - Return the result of the
matchCharsmethod.
- Call the
- If
- Check if the length of
- If the type is not
TokenTypes.STRING_TOKEN, returnfalse.
- If the type is
- Type:
boolean - If the
keymatches the specified item key,trueis returned. Otherwise,falseis returned.

private List<CharSequence> keys() {
if (keys == null) {
List<List<Token>> childrenTokens = childrenTokens();
keys = new ArrayList<>(childrenTokens.size() / 2);
for (int index = 0; index < childrenTokens.size(); index += 2) {
List<Token> itemKey = childrenTokens.get(index);
Token keyToken = itemKey.get(1);
switch(keyToken.type) {
case TokenTypes.STRING_TOKEN:
final StringNode element = new StringNode(keyToken, source, objectsKeysCanBeEncoded);
keys.add(element);
break;
default:
throw new IllegalStateException("Only String are allowed for keys " + TokenTypes.getTypeName(keyToken.type));
}
;
}
}
return keys;
}The keys() method in the ObjectNode class is responsible for retrieving the keys of the object. Here is a step-by-step description of what the method is doing based on its body:
- Check if the
keyslist is null. - If the
keyslist is null, retrieve the children tokens of the object and store them in thechildrenTokenslist. - Create a new
ArrayListwith an initial capacity equal to half of the size of thechildrenTokenslist, and assign it to thekeyslist. - Use a for loop to iterate over the
childrenTokenslist, incrementing the index by 2 each iteration. - Inside the loop, retrieve the
itemKeylist at the current index from thechildrenTokenslist. - Get the second token from the
itemKeylist and assign it to thekeyTokenvariable. - Use a switch statement to check the type of the
keyToken. - If the type of the
keyTokenisSTRING_TOKEN, create a newStringNodeobject using thekeyToken,source, andobjectsKeysCanBeEncodedvariables. - Add the
StringNodeobject to thekeyslist. - If the type of the
keyTokenis notSTRING_TOKEN, throw anIllegalStateExceptionwith a message indicating that only strings are allowed for keys. - After the loop ends, return the
keyslist.
This method retrieves the keys of an object by iterating over the children tokens and extracting the second token from each key. If the token is of type STRING_TOKEN, it creates a StringNode object with the token and adds it to the keys list. If the token's type is different, it throws an exception. Finally, it returns the keys list.

The ArrayNode class represents an array node in a tree structure. It extends the AbstractList class and implements the CollectionNode interface.
public List<List> childrenTokens()
@Override
public List<List<Token>> childrenTokens() {
if (childrenTokens == null) {
childrenTokens = NodeUtils.getChildrenTokens(tokens);
}
return childrenTokens;
}The childrenTokens method in the ArrayNode class, which is defined in the io.nats.jparse.node package, performs the following steps:
-
The method overrides the
childrenTokensmethod from the superclass (Node), indicating that it provides a specific implementation for this method. -
The method has a return type of
List<List<Token>>, which means it returns a list of lists ofTokenobjects. -
When the method is invoked, it first checks if the variable
childrenTokensis null. -
If
childrenTokensis null, it means that the list of children tokens has not been initialized yet. -
In that case, the method invokes the static
getChildrenTokensmethod from theNodeUtilsclass, passing thetokenslist as an argument. -
The
getChildrenTokensmethod is responsible for extracting and organizing the tokens that represent the children of the current node. It likely iterates over thetokenslist, identifies the children tokens, and creates a nested list structure to represent the children tokens of each child node. -
After
getChildrenTokensreturns, the method assigns the returned value to thechildrenTokensvariable, effectively caching the list of children tokens for future invocations. -
Finally, the method returns the value of the
childrenTokensvariable, which now contains the list of children tokens for the currentArrayNode.
Overall, the childrenTokens method provides a way to retrieve the organized children tokens of an ArrayNode. It ensures that the children tokens are computed only once and caches the result for future use, improving performance when invoking this method multiple times.
Node[] elements() {
if (elements == null) {
elements = new Node[childrenTokens().size()];
}
return elements;
}This method is defined in the ArrayNode class in the io.nats.jparse.node package. It returns an array of Node objects. The array represents the elements of the ArrayNode object.
- Check if the
elementsarray isnull. - If the
elementsarray isnull, create a new array ofNodeobjects with the size equal to the number of children tokens of theArrayNodeobject. This ensures that theelementsarray is properly initialized with the correct size. - Return the
elementsarray.
Please note that if the elements array has already been initialized, Step 2 is skipped as it is not necessary to recreate the array. The main purpose of this method is to lazily initialize the elements array when it is first accessed.

public <R> List<R> map(Function<Node, ? extends R> mapper) {
List<R> list = new ArrayList<>(this.size());
Node[] elements = elements();
for (int i = 0; i < elements.length; i++) {
Node element = elements[i];
if (element == null) {
element = getNodeAt(i);
elements[i] = element;
}
list.add(mapper.apply(element));
}
return list;
}The map method in the ArrayNode class is performing the following steps:
-
It takes a
Functionobject calledmapperas a parameter. Themapperfunction is used to transform each element of the array. -
It creates an
ArrayListobject calledlistwith an initial capacity equal to the size of the array. This is done to optimize the performance by reducing the number of reallocations. -
It retrieves an array of
Nodeobjects calledelementsfrom theelements()method. -
It iterates over each element in the
elementsarray using aforloop. -
Within the loop, it retrieves the current element at index
iand assigns it to a variable calledelement. If the element is null, it calls thegetNodeAtmethod to fetch the element at indexiand assigns it back toelement. This is done to ensure that each element is not null before applying themapperfunction. -
It applies the
mapperfunction to theelementusing theapplymethod, and adds the transformed result to thelistusing theaddmethod. -
After processing all the elements, it returns the
listcontaining the transformed elements.
Note: The mapper function can be any operation that you want to perform on each element of the array. It could be a simple transformation, filtering, or any other custom operation based on your requirements.

public Optional<ObjectNode> findObjectNode(Predicate<ObjectNode> predicate) {
final Node[] elements = elements();
ObjectNode node = null;
for (int i = 0; i < elements.length; i++) {
Node element = elements[i];
if (element == null) {
element = getNodeAt(i);
}
if (element.type() == NodeType.OBJECT) {
ObjectNode objectNode = element.asCollection().asObject();
if (predicate.test(objectNode)) {
node = objectNode;
break;
}
}
}
return Optional.ofNullable(node);
}This method is a member of the ArrayNode class located in the io.nats.jparse.node package. It returns an Optional<ObjectNode> based on the given Predicate<ObjectNode>.
The Predicate is used to test each ObjectNode in the array. It is passed as a parameter to the method and allows the caller to define the test condition.
Here is a step-by-step description of what the method does:
-
Get array elements: Retrieve the array elements using the
elements()method, which returns an array ofNodeobjects. -
Iterate over array elements: Iterate over each element in the array using a standard
forloop. -
Handle null elements: Check if the current array element is
null. If so, call thegetNodeAt(i)method to retrieve the element at the given index. -
Check element type: Determine if the current element is of type
OBJECT. This is done by calling thetype()method on theNodeobject and comparing the result withNodeType.OBJECT. -
Convert element to
ObjectNode: If the element is anOBJECTtype, it is converted to anObjectNodeby calling theasCollection().asObject()method. -
Test
ObjectNodewith the predicate: Apply the given predicate to theObjectNodeusing thetest()method. If the test condition is satisfied, theObjectNodeis considered a match. -
Set matched
ObjectNode: If a match is found, assign the matchedObjectNodeto thenodevariable and exit the loop. -
Return
Optional<ObjectNode>: Wrap the matchedObjectNodein anOptionalobject and return it. If no match was found,nullis returned as anOptionalby usingOptional.ofNullable().
Note: The method stops once a matching ObjectNode is found and returns it immediately, without iterating over the remaining array elements.

public Optional<Node> find(Predicate<Node> predicate) {
Node[] elements = elements();
Node node = null;
for (int i = 0; i < elements.length; i++) {
Node element = elements[i];
if (element == null) {
element = getNodeAt(i);
}
if (predicate.test(element)) {
node = element;
break;
}
}
return Optional.ofNullable(node);
}The find method is defined in the io.nats.jparse.node.ArrayNode class. It takes a Predicate<Node> as input and returns an optional Node.
public Optional<Node> find(Predicate<Node> predicate)The find method searches for a Node in the ArrayNode that matches the given predicate. It iterates through the elements of the array and calls the test method of the predicate on each element. If a matching element is found, it is assigned to the node variable and the loop is exited. Finally, the method returns an Optional containing the node or an empty Optional if no matching node was found.
-
predicate: APredicate<Node>used to test each element of the array. It is a functional interface that defines a single abstract methodtestwhich takes aNodeand returns a boolean indicating whether the given node matches the required criteria.
-
elements: An array ofNodeelements obtained from theelementsmethod of theArrayNodeclass. -
node: ANodevariable used to store the matching element. It is initialized asnulland later assigned the matching element if found.
The method uses a for loop to iterate through the elements of the array.
- It initializes the loop counter
ito 0. - The loop runs as long as
iis less than the length of theelementsarray. - In each iteration, the current element at index
iis assigned to theelementvariable. - If the
elementisnull, thegetNodeAtmethod is called to obtain the element at indexi. - The
testmethod of thepredicateis called with theelementas input. If it returnstrue, thenodevariable is assigned the value ofelementand the loop is exited using thebreakstatement. - After the loop, the method returns an
Optionalcontaining the value ofnode.
The method returns an Optional<Node>, which may contain the matching Node if found, or an empty Optional if no matching node was found.

public List<ObjectNode> filterObjects(Predicate<ObjectNode> predicate) {
Node[] elements = elements();
final int length = elements.length;
final List<ObjectNode> arrayList = new ArrayList<>(length / 2);
for (int i = 0; i < length; i++) {
Node element = elements[i];
if (element == null) {
element = getNodeAt(i);
}
if (element.type() == NodeType.OBJECT) {
ObjectNode objectNode = element.asCollection().asObject();
if (predicate.test(objectNode)) {
arrayList.add(objectNode);
}
}
}
return arrayList;
}The filterObjects method in the class io.nats.jparse.node.ArrayNode is performing the following steps:
-
The method takes in a
Predicate<ObjectNode>as a parameter, which allows the caller to specify a condition for filtering the objects. -
It retrieves the elements of the array that the
ArrayNoderepresents by calling theelements()method. -
It initializes a list called
arrayListto store the filtered object nodes. The initial capacity of theArrayListis set tolength / 2, wherelengthis the length of the elements array. -
It then iterates over each element in the array using a
forloop. -
Inside the loop, it checks if the current element is null. If it is null, it calls the
getNodeAt(i)method to retrieve the element at that index. -
It then checks the type of the element using the
type()method. If the type isNodeType.OBJECT, it proceeds with the following steps. -
It converts the element to an
ObjectNodeby calling theasCollection().asObject()method. -
It applies the predicate to the
ObjectNodeby calling thetest(objectNode)method on the predicate. If the predicate returns true, theObjectNodeis added to thearrayListusing theadd(objectNode)method. -
After the loop ends, the method returns the
arrayListcontaining the filteredObjectNodeobjects.
This method allows you to filter an array of objects and receive a list of object nodes that satisfy the specified predicate.

public List<Node> filter(Predicate<Node> predicate) {
Node[] elements = elements();
final int length = elements.length;
final List<Node> arrayList = new ArrayList<>(length / 2);
for (int i = 0; i < length; i++) {
Node element = elements[i];
if (element == null) {
element = getNodeAt(i);
}
if (predicate.test(element)) {
arrayList.add(element);
}
}
return arrayList;
}The filter method in the ArrayNode class is used to filter the elements of the node array based on a given predicate. Here is a step-by-step description of what this method does:
-
Declare a local variable
elementsand assign the result of theelements()method call. This method returns an array ofNodeobjects. -
Get the length of the
elementsarray and store it in a variable calledlength. -
Create a new
ArrayListcalledarrayListwith an initial capacity oflength / 2. -
Start a loop that iterates over the elements of the
elementsarray. The loop index isi, initialized to 0. -
Get the
Nodeobject at indexiand assign it to a local variable calledelement. If theelementisnull, call thegetNodeAt(i)method to retrieve a non-null element. -
Check if the
elementsatisfies the givenpredicate. Thepredicateis passed as a parameter to thefiltermethod and is of typePredicate<Node>. Thetestmethod of thePredicateinterface is used to evaluate theelementagainst the given predicate. -
If the
elementpasses thepredicatetest, add it to thearrayListusing theaddmethod. -
Continue the loop until all elements in the
elementsarray have been processed. -
Return the
arrayListcontaining the elements that passed thepredicatetest.
By using the filter method with a custom predicate, you can easily select and return a subset of elements from the ArrayNode based on a specific condition or criteria.

The BooleanNode class represents a boolean value node in a tree structure. It is part of a broader software engineering implementation where it serves as a scalar node.
public char charAt(int index)
@Override
public char charAt(int index) {
if (value) {
switch(index) {
case 0:
return 't';
case 1:
return 'r';
case 2:
return 'u';
case 3:
return 'e';
default:
throw new IllegalStateException();
}
} else {
switch(index) {
case 0:
return 'f';
case 1:
return 'a';
case 2:
return 'l';
case 3:
return 's';
case 4:
return 'e';
default:
throw new IllegalStateException();
}
}
}This method is an overridden implementation of the charAt method from the CharSequence interface. The method takes an integer index as input and returns the character at that index position from the boolean value stored in the value variable of the BooleanNode object.
public char charAt(int index) @Override
public char charAt(int index) {
if (value) { // if the boolean value is true
switch(index) {
case 0:
return 't'; // returns 't' when index is 0
case 1:
return 'r'; // returns 'r' when index is 1
case 2:
return 'u'; // returns 'u' when index is 2
case 3:
return 'e'; // returns 'e' when index is 3
default:
throw new IllegalStateException(); // throws an exception for any other index
}
} else { // if the boolean value is false
switch(index) {
case 0:
return 'f'; // returns 'f' when index is 0
case 1:
return 'a'; // returns 'a' when index is 1
case 2:
return 'l'; // returns 'l' when index is 2
case 3:
return 's'; // returns 's' when index is 3
case 4:
return 'e'; // returns 'e' when index is 4
default:
throw new IllegalStateException(); // throws an exception for any other index
}
}
}In summary, the charAt method in the BooleanNode class checks the value of the boolean variable value and returns a character based on the index value. If the boolean value is true, it returns 't' for index 0, 'r' for index 1, 'u' for index 2, and 'e' for index 3. If the boolean value is false, it returns 'f' for index 0, 'a' for index 1, 'l' for index 2, 's' for index 3, and 'e' for index 4. Any other index value throws an IllegalStateException.

The PathUtils class is a public class that provides utility methods for working with file paths.
private static Object walkFull(Object object, AtomicInteger i) {
if (object instanceof Map) {
Map map = (Map) object;
((Map<?, ?>) object).keySet().forEach(key -> {
walkFull(map.get(key), i);
i.incrementAndGet();
});
} else if (object instanceof List) {
List list = (List) object;
list.forEach(o -> {
walkFull(o, i);
i.incrementAndGet();
});
} else {
return i.incrementAndGet();
}
return i;
}The walkFull method in class io.nats.jparse.node.support.PathUtils is a recursive method that performs a full traversal of an input object and returns the total number of nodes visited.
Here is a step-by-step description of what the walkFull method does:
-
The method takes two parameters:
-
object- the input object to be traversed -
i- anAtomicIntegerused to track the number of nodes visited
-
-
The method checks if the input
objectis an instance of aMap:- If
objectis aMap, it casts it to aMapand proceeds to step 3. - If not, it checks if the input
objectis an instance of aList:- If
objectis aList, it casts it to aListand proceeds to step 4. - If not, it proceeds to step 5.
- If
- If
-
When
objectis aMap, it iterates over all the keys in the map using thekeySet().forEachmethod:- For each key, it recursively calls the
walkFullmethod passing the value associated with that key and theiparameter. - After the recursive call, it increments the value of
iby callingi.incrementAndGet().
- For each key, it recursively calls the
-
When
objectis aList, it iterates over all the elements in the list using theforEachmethod:- For each element, it recursively calls the
walkFullmethod passing the element and theiparameter. - After the recursive call, it increments the value of
iby callingi.incrementAndGet().
- For each element, it recursively calls the
-
When
objectis neither aMapnor aList, it means it is a leaf node in the traversal and cannot be further traversed.- In this case, it returns the current value of
iincremented by callingi.incrementAndGet().
- In this case, it returns the current value of
-
After traversing all the nodes in the input
object, the method returns the final value ofi.
The purpose of this method is to recursively traverse a given object and count the number of nodes (maps, lists, and leaf nodes) present in the object.

The MockTokenSubList class is a public class that extends the TokenSubList class. This class serves as a mock implementation of the TokenSubList class. It provides a subset view of a list of tokens, allowing for efficient processing and manipulation of the token data. By extending the TokenSubList class, the MockTokenSubList class inherits the behavior and functionality of the parent class, while also providing additional mock functionality for testing purposes.
The CharArrayUtils class is a utility class designed for working with character arrays. It provides various methods and functions that can be used to manipulate and perform operations on character arrays efficiently.
public static String decodeJsonString(char[] chars, int startIndex, int endIndex) {
int length = endIndex - startIndex;
char[] builder = new char[calculateLengthAfterEncoding(chars, startIndex, endIndex, length)];
char c;
int index = startIndex;
int idx = 0;
while (true) {
c = chars[index];
if (c == '\\' && index < (endIndex - 1)) {
index++;
c = chars[index];
if (c != 'u') {
builder[idx] = controlMap[c];
idx++;
} else {
if (index + 4 < endIndex) {
char unicode = getUnicode(chars, index);
builder[idx] = unicode;
index += 4;
idx++;
}
}
} else {
builder[idx] = c;
idx++;
}
if (index >= (endIndex - 1)) {
break;
}
index++;
}
return new String(builder);
}The decodeJsonString method, defined in the io.nats.jparse.node.support.CharArrayUtils class, decodes a JSON string from a character array. Here's a step-by-step description of what the method does:
-
The method takes three parameters:
charsis the character array containing the JSON string,startIndexis the starting index of the substring to decode, andendIndexis the ending index of the substring to decode. -
It calculates the length of the substring by subtracting the
startIndexfrom theendIndex. -
It creates a new character array called
builderwith a length determined by thecalculateLengthAfterEncodingmethod, passing in thechars,startIndex,endIndex, andlengthparameters. -
It initializes a variable
cto store the current character being processed, anindexvariable to keep track of the current index in thecharsarray, and anidxvariable to keep track of the current index in thebuilderarray. -
Enter a loop that continues until
breakis called:- Get the current character
cfrom thecharsarray at the currentindex. - Check if the current character
cis a single quote (') and if theindexis less than (<)(endIndex - 1). - If the above conditions are satisfied, increment the
indexby 1 and get the next charactercfrom thecharsarray.- If the next character
cis not a lowercase 'u', it means it is not a Unicode character, so it can be converted to its corresponding control character using thecontrolMaparray. The converted character is then stored in thebuilderarray at the currentidxindex, andidxis incremented by 1. - If the next character
cis a lowercase 'u', it means it is a Unicode character. Check if there are at least 4 more characters (index + 4 < endIndex) in thecharsarray to form a complete Unicode escape sequence. If so, call thegetUnicodemethod to convert the escape sequence to the corresponding Unicode character, store it in thebuilderarray at the currentidxindex, and increment bothindexandidxby 1.
- If the next character
- If the current character
cis not a single quote, store it in thebuilderarray at the currentidxindex, and incrementidxby 1. - Check if the
indexis greater than or equal to(endIndex - 1). If so, break the loop.
- Get the current character
-
Convert the
buildercharacter array to a string using theStringconstructor and return the decoded JSON string.
Note: The specific details of the calculateLengthAfterEncoding and getUnicode methods are not provided in the given code snippet, so their functionality cannot be described accurately.

private static int calculateLengthAfterEncoding(char[] chars, int startIndex, int endIndex, int length)
private static int calculateLengthAfterEncoding(char[] chars, int startIndex, int endIndex, int length) {
char c;
int index = startIndex;
int controlCharCount = length;
while (true) {
c = chars[index];
if (c == '\\' && index < (endIndex - 1)) {
index++;
c = chars[index];
if (c != 'u') {
controlCharCount -= 1;
} else {
if (index + 4 < endIndex) {
controlCharCount -= 5;
index += 4;
}
}
}
if (index >= (endIndex - 1)) {
break;
}
index++;
}
return controlCharCount;
}The calculateLengthAfterEncoding method in the CharArrayUtils class is used to calculate the length of a character array after encoding.
Here is a step-by-step description of what this method does:
-
Start by initializing the variables
c,index, andcontrolCharCountwith the givenstartIndex,length, andstartIndex, respectively. -
Enter an infinite while loop.
-
At each iteration of the loop, get the character
cat the current indexindexfrom thecharsarray. -
Check if the character
cis a single quote (') and if the current indexindexis less than theendIndex - 1. If both conditions are true, proceed further. -
Increment the index by 1 and get the next character
cat the updated index. -
Check if the character
cis not equal to the letter'u'. If true, decrement thecontrolCharCountby 1. -
If the character
cis equal to'u', check if the current indexindexplus 4 is less than theendIndex. If true, proceed further. -
Decrement the
controlCharCountby 5. -
Increment the index by 4 to skip over the following 4 characters.
-
Check if the index is greater than or equal to
endIndex - 1. If true, break out of the loop and exit. -
Increment the index by 1.
-
Go back to the start of the loop.
-
After exiting the loop, return the final value of
controlCharCount.
Note: This method is used to calculate the length of the character array after encoding by subtracting the length of certain special characters.

public static boolean hasEscapeChar(char[] array, int startIndex, int endIndex) {
char currentChar;
for (int index = startIndex; index < endIndex; index++) {
currentChar = array[index];
if (currentChar == ESCAPE) {
return true;
}
}
return false;
}This method, hasEscapeChar, is defined in the io.nats.jparse.node.support.CharArrayUtils class. It takes in a character array array, a start index startIndex, and an end index endIndex as parameters.
The method iterates through the array from the startIndex to the endIndex (exclusive) using a for loop. For each character currentChar in the array, it checks if it is equal to a constant called ESCAPE.
If the currentChar is equal to ESCAPE, the method returns true. Otherwise, it continues to the next character in the array.
If no character in the range from startIndex to endIndex is equal to ESCAPE, the method returns false.

A TokenSubList is a Java class that extends the AbstractList<Token> interface. It represents a sublist implementation for storing a portion of tokens from a TokenList. This class provides methods for accessing tokens within the sublist, getting the size of the sublist, creating sublists, converting the sublist to an array, and counting the number of children tokens within a specified range relative to a root token. It is designed to be used as part of tokenization or parsing processes in software engineering.
public int countChildren(final int from, final Token rootToken) {
int idx = from;
int count = 0;
final Token[] tokens = this.tokens;
final int length = this.size;
final int offset = this.offset;
final int rootTokenStart = rootToken.startIndex;
final int rootTokenEnd = rootToken.endIndex;
for (; idx < length; idx++) {
Token token = tokens[idx + offset];
if (token.startIndex >= rootTokenStart && token.endIndex <= rootTokenEnd) {
count++;
} else {
break;
}
}
return count;
}The countChildren method in the TokenSubList class, defined in the io.nats.jparse.node.support package, counts the number of child tokens within a specified range, starting from a given index.
Here are the step-by-step details of what the method does based on its body:
- Declare two integer variables,
idxandcount, and initialize them to the values of thefromparameter, which represents the starting index, and 0 respectively. - Create a reference to the
tokensarray of the currentTokenSubListinstance. - Assign the
sizeof theTokenSubListobject to thelengthvariable for easier access. - Assign the
offsetof theTokenSubListobject to theoffsetvariable for easier access. - Get the
startIndexandendIndexof the providedrootTokenobject. - Start a loop which iterates from
idxtolength - 1. - Inside the loop:
a. Get the
Tokenobject at the currentidx + offsetindex from thetokensarray. b. Check if thestartIndexof the token is greater than or equal to therootTokenStartand theendIndexis less than or equal to therootTokenEnd. c. If the above condition is true, increment thecountvariable by one. d. If the above condition is false, break out of the loop. - Return the final value of the
countvariable, which represents the number of child tokens within the specified range and starting from the given index.

The TokenList class is an implementation of a list that stores tokens. It provides methods for adding tokens, accessing tokens by index, clearing the list, creating sub lists, and more. The class also includes methods for managing placeholder tokens and creating compact clones of the list.
public final boolean add(Token token)
@Override
public final boolean add(Token token) {
final int length = tokens.length;
if (index >= length) {
final Token[] newTokens = new Token[length * 2];
System.arraycopy(tokens, 0, newTokens, 0, length);
tokens = newTokens;
}
tokens[index] = token;
index++;
return true;
}The add method in class io.nats.jparse.node.support.TokenList is used to add a Token object to the list of tokens.
Here is a step-by-step description of how the method works:
-
The method is marked as
@Override, indicating that it is overriding a method from a superclass or interface. -
The method signature indicates that it returns a boolean value.
-
The method takes a single parameter,
token, which is of typeToken. This is the object that will be added to the list. -
The method begins by getting the length of the current
tokensarray. -
It checks if the
indexvariable (which presumably tracks the current index where the next token will be added) is greater than or equal to the length of the array. If it is, this means that the array is full and needs to be expanded. -
If the array needs to be expanded, a new array,
newTokens, is created with a length that is double the current length of the array. -
The
System.arraycopymethod is then used to copy the contents of thetokensarray into thenewTokensarray. This ensures that the existing tokens are retained in the new array. -
The
tokensmember variable is then updated to point to the new array. -
The
tokenparameter is added to thetokensarray at the currentindexposition. -
The
indexvariable is incremented to prepare for the next token to be added. -
Finally, the method returns
true, indicating that the token was successfully added to the list.
Overall, the add method ensures that the list of tokens has sufficient capacity to accommodate new tokens, and adds the specified token to the list, updating the index accordingly.

public void placeHolder() {
final int length = tokens.length;
if (index >= length) {
final Token[] newTokens = new Token[length * 2];
System.arraycopy(tokens, 0, newTokens, 0, length);
tokens = newTokens;
}
index++;
}The placeHolder method in the io.nats.jparse.node.support.TokenList class is used to increment the index of the TokenList object and potentially expand its internal array if the index is greater than or equal to the length of the array.
Here is a step-by-step description of what the placeHolder method does based on its body:
- Get the length of the
tokensarray using thelengthfield. - Check if the current value of the
indexfield is greater than or equal to thelengthof thetokensarray. - If the condition is true, it means that the
TokenListobject has reached the end of its internal array. - In this case, create a new array of
Tokenobjects namednewTokenswith a length of twice the current length of thetokensarray. - Use the
System.arraycopymethod to copy the elements from the existingtokensarray to thenewTokensarray.- The starting index for copying is 0 (meaning copying from the beginning of the array).
- The destination array is the
newTokensarray. - The starting index for pasting in the destination array is also 0.
- The number of elements to copy is equal to the length of the
tokensarray.
- Set the
tokensfield of theTokenListobject to thenewTokensarray. This effectively expands the internal array. - Increment the value of the
indexfield by 1.
The purpose of this method is to provide a mechanism for adding new Token objects to the TokenList object. If the index is already at the end of the array, the method will automatically expand the array to accommodate the new elements.

public TokenList compactClone() {
final int length = index;
final Token[] newTokens = new Token[index];
System.arraycopy(tokens, 0, newTokens, 0, length);
return new TokenList(newTokens);
}The compactClone method in the TokenList class is used to create a new instance of TokenList that contains a compact clone of the tokens in the original TokenList object.
Here is a step-by-step description of what the method does:
-
It starts by creating a local variable
lengthand assigning it the value of theindexfield of the current object. Thisindexfield represents the number of tokens currently stored in theTokenListobject. -
It then creates a new array of
Tokenobjects callednewTokenswith a length equal to theindexfield. This ensures that the new array is large enough to hold all the tokens. -
It uses the
System.arraycopymethod to copy the contents of thetokensarray from the originalTokenListobject to thenewTokensarray. This ensures that thenewTokensarray contains a clone of the tokens in the original array. -
Finally, it creates a new
TokenListobject by passing thenewTokensarray to its constructor and returns this new object.
In summary, the compactClone method creates a new TokenList object that contains a compact clone of the tokens in the original TokenList object by copying the contents of the tokens array to a new array.

The CharSequenceUtils class is a utility class that provides various methods for working with CharSequence objects. It offers convenient functions to manipulate and process character sequences efficiently.
The NodeUtils class is a utility class that provides functionality for working with Node objects. It provides various methods to perform operations on nodes, making it easier to manipulate and interact with these objects.
public static Node createNode(final List tokens, final CharSource source, boolean objectsKeysCanBeEncoded)
public static Node createNode(final List<Token> tokens, final CharSource source, boolean objectsKeysCanBeEncoded) {
final NodeType nodeType = NodeType.tokenTypeToElement(tokens.get(0).type);
switch(nodeType) {
case ARRAY:
return new ArrayNode((TokenSubList) tokens, source, objectsKeysCanBeEncoded);
case INT:
return new NumberNode(tokens.get(0), source, NodeType.INT);
case FLOAT:
return new NumberNode(tokens.get(0), source, NodeType.FLOAT);
case OBJECT:
return new ObjectNode((TokenSubList) tokens, source, objectsKeysCanBeEncoded);
case STRING:
return new StringNode(tokens.get(0), source);
case BOOLEAN:
return new BooleanNode(tokens.get(0), source);
case NULL:
return new NullNode(tokens.get(0), source);
case PATH_INDEX:
return new IndexPathNode(tokens.get(0), source);
case PATH_KEY:
return new KeyPathNode(tokens.get(0), source);
default:
throw new IllegalStateException();
}
}The createNode method in the NodeUtils class is responsible for creating a Node object based on the provided list of tokens and other parameters. Here is a step-by-step explanation of what this method does:
-
The method takes three parameters:
-
tokens- a list ofTokenobjects -
source- aCharSourceobject -
objectsKeysCanBeEncoded- a boolean value indicating whether object keys can be encoded
-
-
It extracts the type of the first token in the list using the
typefield of theTokenobject and maps it to a correspondingNodeTypeusingNodeType.tokenTypeToElement(tokens.get(0).type). -
It uses a
switchstatement to determine the type ofNodeobject to create based on the mappedNodeType. -
If the
NodeTypeisARRAY, it creates a newArrayNodeobject using thetokens,source, andobjectsKeysCanBeEncodedparameters, and returns it. -
If the
NodeTypeisINT, it creates a newNumberNodeobject with the first token,source, andNodeType.INT, and returns it. -
If the
NodeTypeisFLOAT, it creates a newNumberNodeobject with the first token,source, andNodeType.FLOAT, and returns it. -
If the
NodeTypeisOBJECT, it creates a newObjectNodeobject using thetokens,source, andobjectsKeysCanBeEncodedparameters, and returns it. -
If the
NodeTypeisSTRING, it creates a newStringNodeobject with the first token andsource, and returns it. -
If the
NodeTypeisBOOLEAN, it creates a newBooleanNodeobject with the first token andsource, and returns it. -
If the
NodeTypeisNULL, it creates a newNullNodeobject with the first token andsource, and returns it. -
If the
NodeTypeisPATH_INDEX, it creates a newIndexPathNodeobject with the first token andsource, and returns it. -
If the
NodeTypeisPATH_KEY, it creates a newKeyPathNodeobject with the first token andsource, and returns it. -
If none of the above
NodeTypecases match, it throws anIllegalStateException.
That's the step-by-step description of the createNode method in the NodeUtils class.

public static Node createNodeForObject(final List theTokens, final CharSource source, boolean objectsKeysCanBeEncoded)
public static Node createNodeForObject(final List<Token> theTokens, final CharSource source, boolean objectsKeysCanBeEncoded) {
final Token rootToken = theTokens.get(1);
final List<Token> tokens = theTokens.subList(1, theTokens.size());
final NodeType nodeType = NodeType.tokenTypeToElement(rootToken.type);
switch(nodeType) {
case ARRAY:
return new ArrayNode((TokenSubList) tokens, source, objectsKeysCanBeEncoded);
case INT:
return new NumberNode(tokens.get(0), source, NodeType.INT);
case FLOAT:
return new NumberNode(tokens.get(0), source, NodeType.FLOAT);
case OBJECT:
return new ObjectNode((TokenSubList) tokens, source, objectsKeysCanBeEncoded);
case STRING:
return new StringNode(tokens.get(0), source);
case BOOLEAN:
return new BooleanNode(tokens.get(0), source);
case NULL:
return new NullNode(tokens.get(0), source);
default:
throw new IllegalStateException();
}
}The createNodeForObject method, defined in the NodeUtils class in the io.nats.jparse.node.support package, takes in a list of tokens, a character source, and a boolean indicating whether object keys can be encoded. It returns a Node object based on the type of the root token.
Here is a step-by-step description of what the method does:
- It retrieves the root token from the input list of tokens and assigns it to the local variable
rootToken. - It creates a new sublist of tokens (
tokens) by excluding the first token (root token) from the input list using thesubListmethod. - It determines the
NodeType(enumeration) corresponding to the type of the root token using thetokenTypeToElementmethod and assigns it to the local variablenodeType. - It uses a switch statement on the
nodeTypeto handle different cases:- If the
nodeTypeisARRAY, it creates a newArrayNodeobject passing in thetokens,source, andobjectsKeysCanBeEncodedarguments and returns it. - If the
nodeTypeisINT, it creates a newNumberNodeobject passing in the first token fromtokens,source, and theNodeType.INTenum value, and returns it. - If the
nodeTypeisFLOAT, it creates a newNumberNodeobject passing in the first token fromtokens,source, and theNodeType.FLOATenum value, and returns it. - If the
nodeTypeisOBJECT, it creates a newObjectNodeobject passing in thetokens,source, andobjectsKeysCanBeEncodedarguments and returns it. - If the
nodeTypeisSTRING, it creates a newStringNodeobject passing in the first token fromtokensandsource, and returns it. - If the
nodeTypeisBOOLEAN, it creates a newBooleanNodeobject passing in the first token fromtokensandsource, and returns it. - If the
nodeTypeisNULL, it creates a newNullNodeobject passing in the first token fromtokensandsource, and returns it. - If none of the above cases match, it throws an
IllegalStateException.
- If the
- The method ends.
This method is responsible for creating and returning different types of Node objects based on the type of the root token.

The NumberParseResult class represents the result of a number parsing operation. It provides methods to access the end index of the parsed number and to check if the parsed number was a float. The class also overrides the equals, hashCode, and toString methods for proper object comparison and string representation.

The JsonStrictParser class is an implementation of the JsonParser interface. It uses a strict JSON parsing algorithm and does not accept JSON strings that are not strictly compliant with the JSON RFC.
private List<Token> scan(final CharSource source, TokenList tokens) {
nestLevel = 0;
int ch = source.nextSkipWhiteSpace();
switch(ch) {
case OBJECT_START_TOKEN:
parseObject(source, tokens);
break;
case ARRAY_START_TOKEN:
parseArray(source, tokens);
break;
case TRUE_BOOLEAN_START:
parseTrue(source, tokens);
break;
case FALSE_BOOLEAN_START:
parseFalse(source, tokens);
break;
case NULL_START:
parseNull(source, tokens);
break;
case STRING_START_TOKEN:
parseString(source, tokens);
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
parseNumber(source, tokens);
break;
default:
throw new UnexpectedCharacterException("Scanning JSON", "Unexpected character", source, (char) ch);
}
source.checkForJunk();
return tokens;
}The scan method is defined in the JsonStrictParser class in the package io.nats.jparse.parser.indexoverlay. It takes two parameters: a CharSource object and a TokenList object.
Here is a step-by-step description of what the scan method does based on its body:
-
It initializes the
nestLevelvariable to 0. -
It calls the
nextSkipWhiteSpacemethod on thesourceobject to get the next non-whitespace character and assigns it to thechvariable. -
It uses a switch statement to perform different actions based on the value of
ch:-
If
chis equal toOBJECT_START_TOKEN, it calls theparseObjectmethod, passing thesourceandtokensobjects. -
If
chis equal toARRAY_START_TOKEN, it calls theparseArraymethod, passing thesourceandtokensobjects. -
If
chis equal toTRUE_BOOLEAN_START, it calls theparseTruemethod, passing thesourceandtokensobjects. -
If
chis equal toFALSE_BOOLEAN_START, it calls theparseFalsemethod, passing thesourceandtokensobjects. -
If
chis equal toNULL_START, it calls theparseNullmethod, passing thesourceandtokensobjects. -
If
chis equal toSTRING_START_TOKEN, it calls theparseStringmethod, passing thesourceandtokensobjects. -
If
chis equal to any of the number-related tokens (NUM_0,NUM_1, ...,NUM_9,MINUS,PLUS), it calls theparseNumbermethod, passing thesourceandtokensobjects. -
If none of the above cases match, it throws an
UnexpectedCharacterExceptionwith a message indicating that an unexpected character was encountered.
-
-
After the switch statement, it calls the
checkForJunkmethod on thesourceobject to check if there is any remaining junk after parsing the JSON. -
Finally, it returns the
tokensobject.
That's the step-by-step description of what the scan method does based on its body.

private void parseArray(final CharSource source, final TokenList tokens) {
levelCheck(source);
final int startSourceIndex = source.getIndex();
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean done = false;
while (!done) {
done = parseArrayItem(source, tokens);
if (!done) {
done = source.findCommaOrEndForArray();
}
}
final Token arrayToken = new Token(startSourceIndex, source.getIndex(), TokenTypes.ARRAY_TOKEN);
tokens.set(tokenListIndex, arrayToken);
}The parseArray method in class io.nats.jparse.parser.indexoverlay.JsonStrictParser is responsible for parsing an array from a given character source.
Here is a step-by-step description of what this method does:
- It starts by calling the
levelCheckmethod, which verifies that the parser is at the correct level before parsing the array. - It stores the current index of the character source and the index of the token list.
- It adds a placeholder token to the token list using the
tokens.placeHolder()method. - It enters a loop which continues until the parsing of the array is done.
- Inside the loop, it calls the
parseArrayItemmethod to parse each item in the array. The method returns a boolean indicating whether the parsing is done or not. - If the parsing is not done, it calls the
source.findCommaOrEndForArray()method to find the next comma or the end of the array in the character source. - The loop continues until the parsing of the array is done.
- After the loop, it creates a
Tokenobject representing the parsed array, using the start index and the current index of the character source. The token type is set toTokenTypes.ARRAY_TOKEN. - Finally, it updates the placeholder token in the token list with the newly created array token using the
tokens.set(tokenListIndex, arrayToken)method.
In summary, the parseArray method iterates over the items in the array, parses each item using the parseArrayItem method, and then creates a token representing the parsed array.

private boolean parseArrayItem(CharSource source, TokenList tokens) {
char startChar = source.getCurrentChar();
int ch = source.nextSkipWhiteSpace();
switch(ch) {
case OBJECT_START_TOKEN:
parseObject(source, tokens);
break;
case ARRAY_START_TOKEN:
parseArray(source, tokens);
break;
case TRUE_BOOLEAN_START:
parseTrue(source, tokens);
break;
case FALSE_BOOLEAN_START:
parseFalse(source, tokens);
break;
case NULL_START:
parseNull(source, tokens);
break;
case STRING_START_TOKEN:
parseString(source, tokens);
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
parseNumber(source, tokens);
if (source.getCurrentChar() == ARRAY_END_TOKEN || source.getCurrentChar() == ARRAY_SEP) {
if (source.getCurrentChar() == ARRAY_END_TOKEN) {
source.next();
return true;
}
}
break;
case ARRAY_END_TOKEN:
if (startChar == ARRAY_SEP) {
throw new UnexpectedCharacterException("Parsing Array Item", "Trailing comma", source, (char) ch);
}
source.next();
return true;
default:
throw new UnexpectedCharacterException("Parsing Array Item", "Unexpected character", source, (char) ch);
}
return false;
}The parseArrayItem method is defined in the JsonStrictParser class in the io.nats.jparse.parser.indexoverlay package. It takes two parameters, CharSource source and TokenList tokens, and returns a boolean value.
Here is a step-by-step description of what the parseArrayItem method does based on its body:
- It retrieves the current character from the
sourceusing thegetCurrentCharmethod and assigns it to thestartCharvariable. - It reads the next character from the
sourcewhile skipping any whitespaces using thenextSkipWhiteSpacemethod and assigns it to thechvariable. - It performs a switch-case statement based on the value of
chto determine the action to take:- If
chis equal toOBJECT_START_TOKEN, it calls theparseObjectmethod passingsourceandtokensas arguments. - If
chis equal toARRAY_START_TOKEN, it calls theparseArraymethod passingsourceandtokensas arguments. - If
chis equal toTRUE_BOOLEAN_START, it calls theparseTruemethod passingsourceandtokensas arguments. - If
chis equal toFALSE_BOOLEAN_START, it calls theparseFalsemethod passingsourceandtokensas arguments. - If
chis equal toNULL_START, it calls theparseNullmethod passingsourceandtokensas arguments. - If
chis equal toSTRING_START_TOKEN, it calls theparseStringmethod passingsourceandtokensas arguments. - If
chis equal to any of the numeric characters (0-9) or the symbols '-' or '+', it calls theparseNumbermethod passingsourceandtokensas arguments.- After parsing the number, if the current character is either
ARRAY_END_TOKENorARRAY_SEP, it checks if the current character isARRAY_END_TOKEN.- If it is, it advances the
sourceusing thenextmethod and returnstrue.
- If it is, it advances the
- After parsing the number, if the current character is either
- If
chis equal toARRAY_END_TOKEN, it first checks if thestartCharisARRAY_SEP.- If it is, it throws an
UnexpectedCharacterExceptionwith the message "Parsing Array Item: Trailing comma",sourceand the character as arguments. - If it is not, it advances the
sourceusing thenextmethod and returnstrue.
- If it is, it throws an
- If none of the above cases match, it throws an
UnexpectedCharacterExceptionwith the message "Parsing Array Item: Unexpected character",source, and the character as arguments.
- If
- If none of the cases match, it returns
false.
The purpose of the parseArrayItem method is to parse an item within a JSON array and add tokens to the TokenList for further processing.
private boolean parseKey(final CharSource source, final TokenList tokens) {
final char startChar = source.getCurrentChar();
int ch = source.nextSkipWhiteSpace();
final int startIndex = source.getIndex() - 1;
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean found = false;
switch(ch) {
case STRING_START_TOKEN:
final int strStartIndex = startIndex + 1;
final int strEndIndex;
if (objectsKeysCanBeEncoded) {
strEndIndex = source.findEndOfEncodedString();
} else {
strEndIndex = source.findEndString();
}
tokens.add(new Token(strStartIndex + 1, strEndIndex, TokenTypes.STRING_TOKEN));
found = true;
break;
case OBJECT_END_TOKEN:
if (startChar == OBJECT_ATTRIBUTE_SEP) {
throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
}
tokens.undoPlaceholder();
return true;
default:
throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
}
boolean done = source.findObjectEndOrAttributeSep();
if (!done && found) {
tokens.set(tokenListIndex, new Token(startIndex + 1, source.getIndex(), TokenTypes.ATTRIBUTE_KEY_TOKEN));
} else if (found && done) {
throw new UnexpectedCharacterException("Parsing key", "Not found", source);
}
return done;
}The parseKey method in the JsonStrictParser class is responsible for parsing a key from a CharSource and adding it to a TokenList. Here is a step-by-step description of this method:
- The method starts by getting the current character from the
CharSource. - It then skips any whitespace characters and gets the next character from the
CharSource. - The current index of the
CharSourceis stored as the starting index of the key. - The current index of the
TokenListis stored as the token list index. - A placeholder token is added to the
TokenList. - A switch statement is used to handle different cases based on the value of the next character:
- If the next character is a
STRING_START_TOKEN, the method proceeds to extract the string key. - If the next character is an
OBJECT_END_TOKEN, the method checks if the start character is anOBJECT_ATTRIBUTE_SEPand throws an exception if so. Otherwise, it undoes the placeholder token and returnstrue. - If none of the above cases match, an exception is thrown.
- If the next character is a
- If a string key is found, the method determines the end index of the string and adds a new token to the
TokenListrepresenting the string key. - A boolean variable
doneis set based on whether the method can find the end of the object or the attribute separator. - If the parsing is not done (
!done) and a key is found (foundistrue), the method updates the placeholder token in theTokenListwith the start and end indices of the key. - If a key is found (
foundistrue) and the parsing is done (doneistrue), an exception is thrown. - Finally, the method returns the value of
done.
This method is responsible for parsing a key from a JSON object and updating the TokenList with the parsed key token.

private boolean parseValue(final CharSource source, TokenList tokens) {
int ch = source.nextSkipWhiteSpace();
final int startIndex = source.getIndex();
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
switch(ch) {
case OBJECT_START_TOKEN:
parseObject(source, tokens);
break;
case ARRAY_START_TOKEN:
parseArray(source, tokens);
break;
case TRUE_BOOLEAN_START:
parseTrue(source, tokens);
break;
case FALSE_BOOLEAN_START:
parseFalse(source, tokens);
break;
case NULL_START:
parseNull(source, tokens);
break;
case STRING_START_TOKEN:
parseString(source, tokens);
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
parseNumber(source, tokens);
break;
default:
throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, ch);
}
source.skipWhiteSpace();
switch(source.getCurrentChar()) {
case OBJECT_END_TOKEN:
if (source.getIndex() == tokenListIndex) {
throw new UnexpectedCharacterException("Parsing Value", "Key separator before value", source);
}
tokens.set(tokenListIndex, new Token(startIndex, source.getIndex(), TokenTypes.ATTRIBUTE_VALUE_TOKEN));
return true;
case OBJECT_ATTRIBUTE_SEP:
if (source.getIndex() == tokenListIndex) {
throw new UnexpectedCharacterException("Parsing Value", "Key separator before value", source);
}
tokens.set(tokenListIndex, new Token(startIndex, source.getIndex(), TokenTypes.ATTRIBUTE_VALUE_TOKEN));
return false;
default:
throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, source.getCurrentChar());
}
}The parseValue method in the JsonStrictParser class is responsible for parsing a single JSON value from a given character source (source) and adding the corresponding token to a token list (tokens). Here is a step-by-step description of what the method does:
- Read the next character from the character source while skipping any white space characters.
- Get the current index of the character source (
startIndex) and the current index of the token list (tokenListIndex). - Add a placeholder token to the token list at the current index.
- Use a switch statement to check the value of the character read in step 1.
- If the character is the start of an object (
OBJECT_START_TOKEN), call theparseObjectmethod to parse the object and add the corresponding token(s) to the token list. - If the character is the start of an array (
ARRAY_START_TOKEN), call theparseArraymethod to parse the array and add the corresponding token(s) to the token list. - If the character is the start of the boolean value
true(TRUE_BOOLEAN_START), call theparseTruemethod to parse the boolean value and add the corresponding token(s) to the token list. - If the character is the start of the boolean value
false(FALSE_BOOLEAN_START), call theparseFalsemethod to parse the boolean value and add the corresponding token(s) to the token list. - If the character is the start of the value
null(NULL_START), call theparseNullmethod to parse the null value and add the corresponding token(s) to the token list. - If the character is the start of a string (
STRING_START_TOKEN), call theparseStringmethod to parse the string value and add the corresponding token(s) to the token list. - If the character is a digit (
NUM_0toNUM_9) or a sign (MINUSorPLUS), call theparseNumbermethod to parse the number value and add the corresponding token(s) to the token list. - If the character does not match any of the above cases, throw an
UnexpectedCharacterExceptionwith an appropriate error message.
- If the character is the start of an object (
- Skip any white space characters after parsing the value.
- Use a switch statement to check the current character in the character source.
- If the character is the end of an object (
OBJECT_END_TOKEN), check if the current index of the character source is the same as thetokenListIndex. If they are equal, throw anUnexpectedCharacterExceptionwith an error message indicating "Key separator before value". Otherwise, set the token at thetokenListIndexto be a new token representing the parsed value and return true from the method. - If the character is the attribute separator (
OBJECT_ATTRIBUTE_SEP), check if the current index of the character source is the same as thetokenListIndex. If they are equal, throw anUnexpectedCharacterExceptionwith an error message indicating "Key separator before value". Otherwise, set the token at thetokenListIndexto be a new token representing the parsed value and return false from the method. - If the current character does not match any of the above cases, throw an
UnexpectedCharacterExceptionwith an appropriate error message.
- If the character is the end of an object (
private void parseObject(final CharSource source, TokenList tokens) {
levelCheck(source);
final int startSourceIndex = source.getIndex();
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean done = false;
while (!done) {
done = parseKey(source, tokens);
if (!done)
done = parseValue(source, tokens);
}
source.next();
tokens.set(tokenListIndex, new Token(startSourceIndex, source.getIndex(), TokenTypes.OBJECT_TOKEN));
}The parseObject method is a private method defined in the class io.nats.jparse.parser.indexoverlay.JsonStrictParser. This method takes two parameters: source, which is an instance of the CharSource class, and tokens, which is an instance of the TokenList class.
The purpose of this method is to parse an object from the given source and add the corresponding token to the tokens list.
Here is a step-by-step description of what the parseObject method is doing based on its body:
-
The method starts by calling the
levelCheckmethod passing thesourceas a parameter, which ensures that the nesting level of the JSON object is within certain bounds. -
The next two lines of code store the current index of the
sourceand the index of thetokenslist. -
The method then adds a placeholder token to the
tokenslist using theplaceHoldermethod. -
The method enters a loop that continues until the parsing is done.
-
Inside the loop, the method first calls the
parseKeymethod passing thesourceandtokensas parameters. TheparseKeymethod is not shown in the provided code, but it is assumed to return a boolean value indicating whether the key parsing is done or not. The return value is stored in thedonevariable. -
If the key parsing is not done (i.e.,
doneis false), the method calls theparseValuemethod passing thesourceandtokensas parameters. TheparseValuemethod is not shown in the provided code, but it is assumed to return a boolean value indicating whether the value parsing is done or not. The return value is also stored in thedonevariable. -
The loop continues until both the key and value parsing is done.
-
After the loop is done, the next line of code calls the
nextmethod on thesourceto advance to the next character in the input. -
Finally, the last line of code sets the token at the
tokenListIndexin thetokenslist to a newTokenobject. ThisTokenobject is created with thestartSourceIndex, which is the starting index of the source, the current index of the source, and theTokenTypes.OBJECT_TOKENtype.
Overall, the parseObject method is responsible for parsing a JSON object from the source and adding a token representing that object to the tokens list.

private void levelCheck(CharSource source) {
nestLevel++;
if (nestLevel > NEST_LEVEL) {
throw new UnexpectedCharacterException("Next level violation", "Too many levels " + nestLevel, source);
}
}This method is defined in the JsonStrictParser class, which resides in the io.nats.jparse.parser.indexoverlay package. It performs the following steps:
- Increments the value of the
nestLevelvariable by 1. - Checks if the value of
nestLevelis greater thanNEST_LEVEL. - If the condition evaluates to true, it throws an
UnexpectedCharacterException.- The exception message is set to "Next level violation".
- The exception details include "Too many levels" followed by the value of
nestLevel. - The
sourceparameter is also passed to the exception constructor.
This method is used to ensure that the nesting level in a JSON input does not exceed a predefined threshold (NEST_LEVEL). If the nesting level exceeds this threshold, an exception is thrown.

The JsonFastParser class is an implementation of the JsonParser interface that provides methods for scanning and parsing JSON strings. It offers functionality for scanning a character source and returning a list of tokens, as well as parsing a character source and returning a root node representing the parsed JSON. The class also includes default methods for parsing and scanning strings and extends the ParseConstants interface, which defines constants used for parsing JSON strings.
private List<Token> scan(final CharSource source, TokenList tokens) {
int ch = source.nextSkipWhiteSpace();
switch(ch) {
case OBJECT_START_TOKEN:
parseObject(source, tokens);
break;
case ARRAY_START_TOKEN:
parseArray(source, tokens);
break;
case TRUE_BOOLEAN_START:
parseTrue(source, tokens);
break;
case FALSE_BOOLEAN_START:
parseFalse(source, tokens);
break;
case NULL_START:
parseNull(source, tokens);
break;
case STRING_START_TOKEN:
parseString(source, tokens);
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
parseNumber(source, tokens);
break;
default:
throw new UnexpectedCharacterException("Scanning JSON", "Unexpected character", source, (char) ch);
}
return tokens;
}The method scan is defined in the JsonFastParser class in the package io.nats.jparse.parser.indexoverlay. It takes two parameters, a CharSource object named source and a TokenList object named tokens. The purpose of this method is to scan the given input source character by character and determine the appropriate action to take based on the encountered character.
Here is a step-by-step description of what the scan method does based on its body:
-
The method starts by calling the
nextSkipWhiteSpacemethod on thesourceobject, which returns the next non-whitespace character from the input source. This character is stored in the variablech. -
A switch statement is used to determine the action to take based on the value of
ch. -
If
chis equal toOBJECT_START_TOKEN, theparseObjectmethod is called with thesourceandtokensobjects as parameters. This method parses an object from the input source and adds the corresponding tokens to thetokenslist. -
If
chis equal toARRAY_START_TOKEN, theparseArraymethod is called with thesourceandtokensobjects as parameters. This method parses an array from the input source and adds the corresponding tokens to thetokenslist. -
If
chis equal toTRUE_BOOLEAN_START, theparseTruemethod is called with thesourceandtokensobjects as parameters. This method parses atrueboolean value from the input source and adds the corresponding token to thetokenslist. -
If
chis equal toFALSE_BOOLEAN_START, theparseFalsemethod is called with thesourceandtokensobjects as parameters. This method parses afalseboolean value from the input source and adds the corresponding token to thetokenslist. -
If
chis equal toNULL_START, theparseNullmethod is called with thesourceandtokensobjects as parameters. This method parses anullvalue from the input source and adds the corresponding token to thetokenslist. -
If
chis equal toSTRING_START_TOKEN, theparseStringmethod is called with thesourceandtokensobjects as parameters. This method parses a string from the input source and adds the corresponding token to thetokenslist. -
If
chis equal toNUM_0,NUM_1,NUM_2,NUM_3,NUM_4,NUM_5,NUM_6,NUM_7,NUM_8,NUM_9,MINUS, orPLUS, theparseNumbermethod is called with thesourceandtokensobjects as parameters. This method parses a number from the input source and adds the corresponding token to thetokenslist. -
If none of the above cases match, an
UnexpectedCharacterExceptionis thrown with an error message indicating that the character is unexpected. -
Finally, the
tokenslist is returned.
In summary, the scan method scans the input source character by character and performs different parsing actions based on the encountered character, such as parsing objects, arrays, booleans, strings, numbers, or throwing an exception for unexpected characters. The method then returns the list of tokens that were parsed.

private void parseArray(final CharSource source, final TokenList tokens) {
final int startSourceIndex = source.getIndex();
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean done = false;
while (!done) {
done = parseArrayItem(source, tokens);
}
final Token arrayToken = new Token(startSourceIndex, source.getIndex(), TokenTypes.ARRAY_TOKEN);
tokens.set(tokenListIndex, arrayToken);
}The parseArray method in the JsonFastParser class is responsible for parsing an array from a given CharSource and storing the resulting tokens in a TokenList object.
Here is a step-by-step description of what the method does:
- It starts by storing the current index of the
CharSourcein a variable calledstartSourceIndex. - It also stores the current index of the
TokenListin a variable calledtokenListIndex. - It adds a placeholder token to the
TokenListusing theplaceHolder()method. This placeholder token will be replaced with the actual array token later. - It initializes a boolean variable
doneto false. This variable will be used to determine when to stop parsing the array. - It enters a while loop that continues until the
donevariable becomes true. - Inside the while loop, it calls the
parseArrayItemmethod, passing thesourceandtokensobjects. This method is responsible for parsing a single item of the array. - The return value of the
parseArrayItemmethod is then used to update thedonevariable. If theparseArrayItemmethod returns true, it means that it has successfully parsed an array item. If it returns false, it means that there are no more array items to parse, and the loop should be terminated. - After the while loop finishes, it creates a
Tokenobject calledarrayTokenwith the start and end indices of the array in theCharSource, and the typeTokenTypes.ARRAY_TOKEN. - Finally, it replaces the placeholder token in the
TokenListat thetokenListIndexwith thearrayTokenusing thesetmethod.
This completes the step-by-step description of the parseArray method in the JsonFastParser class.

private boolean parseArrayItem(CharSource source, TokenList tokens) {
char ch = (char) source.nextSkipWhiteSpace();
forLoop: for (; ch != ETX; ch = (char) source.nextSkipWhiteSpace()) {
switch(ch) {
case OBJECT_START_TOKEN:
parseObject(source, tokens);
break forLoop;
case ARRAY_START_TOKEN:
parseArray(source, tokens);
break forLoop;
case TRUE_BOOLEAN_START:
parseTrue(source, tokens);
break forLoop;
case FALSE_BOOLEAN_START:
parseFalse(source, tokens);
break forLoop;
case NULL_START:
parseNull(source, tokens);
break forLoop;
case STRING_START_TOKEN:
parseString(source, tokens);
break forLoop;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
parseNumber(source, tokens);
break forLoop;
case ARRAY_END_TOKEN:
source.next();
return true;
case ARRAY_SEP:
source.next();
return false;
default:
throw new UnexpectedCharacterException("Parsing Array Item", "Unexpected character", source, ch);
}
}
if (source.getCurrentChar() == ARRAY_END_TOKEN) {
source.next();
return true;
}
return false;
}The method parseArrayItem in the JsonFastParser class is used to parse an individual item within a JSON array. Here is a step-by-step description of what this method does:
-
The method takes two parameters:
source, which is the source of the characters to be parsed, andtokens, which is a list to store the parsed tokens. -
It starts by reading the next character from the
sourceand assigns it to the variablech. The whitespace characters are skipped. -
It enters a
forloop, labeled asforLoop, which iterates until the characterchisETX(End of Text). -
Inside the loop, there is a
switchstatement that checks the value of the characterch. -
If
chis equal toOBJECT_START_TOKEN, it calls theparseObjectmethod to parse the JSON object, and thenbreak forLoopis executed, which exits theforloop. -
If
chis equal toARRAY_START_TOKEN, it calls theparseArraymethod to parse the JSON array, and thenbreak forLoopis executed. -
If
chis equal toTRUE_BOOLEAN_START, it calls theparseTruemethod to parse a boolean value of true, and thenbreak forLoopis executed. -
If
chis equal toFALSE_BOOLEAN_START, it calls theparseFalsemethod to parse a boolean value of false, and thenbreak forLoopis executed. -
If
chis equal toNULL_START, it calls theparseNullmethod to parse a null value, and thenbreak forLoopis executed. -
If
chis equal toSTRING_START_TOKEN, it calls theparseStringmethod to parse a string value, and thenbreak forLoopis executed. -
If
chis a numeric digit (NUM_0toNUM_9) or a minus or plus sign (MINUSorPLUS), it calls theparseNumbermethod to parse a numeric value, and thenbreak forLoopis executed. -
If
chis equal toARRAY_END_TOKEN, it moves to the next character in thesourceand returnstrue, indicating that the parsing of the array item is complete. -
If
chis equal toARRAY_SEP, it moves to the next character in thesourceand returnsfalse, indicating that there are more items in the array to be parsed. -
If none of the above cases match, it throws an
UnexpectedCharacterExceptionwith an error message indicating that an unexpected character was encountered while parsing the array item. -
After the
forloop, it checks if the current character in thesourceis equal toARRAY_END_TOKEN. If it is, the method moves to the next character, returnstrue, indicating that the parsing of the array item is complete. -
If the current character is not
ARRAY_END_TOKEN, the method returnsfalse, indicating that there are additional array items to be parsed.
That's the step-by-step description of the parseArrayItem method.
private boolean parseKey(final CharSource source, final TokenList tokens) {
int ch = source.nextSkipWhiteSpace();
final int startIndex = source.getIndex() - 1;
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean found = false;
switch(ch) {
case STRING_START_TOKEN:
final int strStartIndex = startIndex + 1;
final int strEndIndex;
if (objectsKeysCanBeEncoded) {
strEndIndex = source.findEndOfEncodedString();
} else {
strEndIndex = source.findEndString();
}
tokens.add(new Token(strStartIndex + 1, strEndIndex, TokenTypes.STRING_TOKEN));
found = true;
break;
case OBJECT_END_TOKEN:
tokens.undoPlaceholder();
return true;
default:
throw new UnexpectedCharacterException("Parsing key", "Unexpected character found", source);
}
boolean done = source.findObjectEndOrAttributeSep();
if (!done && found) {
tokens.set(tokenListIndex, new Token(startIndex + 1, source.getIndex(), TokenTypes.ATTRIBUTE_KEY_TOKEN));
} else if (found && done) {
throw new UnexpectedCharacterException("Parsing key", "Not found", source);
}
return done;
}The parseKey method in the class io.nats.jparse.parser.indexoverlay.JsonFastParser is used to parse a key from a JSON object. Here is a step-by-step description of what the method does based on its body:
-
It begins by reading the next character from the input source and skipping any whitespace characters.
-
The method keeps track of the starting index of the key and the current index of the token list.
-
It adds a placeholder token to the token list to reserve a position for the parsed key.
-
The method then checks the value of the currently read character (ch) using a switch statement.
-
If the character is the start of a string (STRING_START_TOKEN), the method proceeds to parse the string key. It determines the start position of the string key and then finds the end position by either decoding the string or finding the end of the string. It adds a new token to the token list with the start and end positions of the string key, marked as a STRING_TOKEN. It sets the "found" variable to true.
-
If the character is an object end token (OBJECT_END_TOKEN), it means that the parsing of the current JSON object is complete. The method removes the placeholder token from the token list and returns true to indicate that the parsing of the key is done.
-
If the character is neither a string start token nor an object end token, it throws an UnexpectedCharacterException with an appropriate error message indicating that an unexpected character was found while parsing the key.
-
After handling the character, the method proceeds to find the end of the current JSON object or the separator between attributes.
-
If the end of the object or attribute separator is not found and a key has been found, it updates the token list with the correct start and end positions of the key as an ATTRIBUTE_KEY_TOKEN.
-
If a key has been found but the end of the object or attribute separator is found, it throws an UnexpectedCharacterException with an appropriate error message indicating that the end was not found.
-
Finally, the method returns the value of the "done" variable, which indicates whether the parsing of the key is complete or not.
This method provides a step-by-step process for parsing a key from a JSON object and handles different scenarios like string keys, object ends, and unexpected characters.

private boolean parseValue(final CharSource source, TokenList tokens) {
int ch = source.nextSkipWhiteSpace();
final int startIndex = source.getIndex();
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
switch(ch) {
case OBJECT_START_TOKEN:
parseObject(source, tokens);
break;
case ARRAY_START_TOKEN:
parseArray(source, tokens);
break;
case TRUE_BOOLEAN_START:
parseTrue(source, tokens);
break;
case FALSE_BOOLEAN_START:
parseFalse(source, tokens);
break;
case NULL_START:
parseNull(source, tokens);
break;
case STRING_START_TOKEN:
parseString(source, tokens);
break;
case NUM_0:
case NUM_1:
case NUM_2:
case NUM_3:
case NUM_4:
case NUM_5:
case NUM_6:
case NUM_7:
case NUM_8:
case NUM_9:
case MINUS:
case PLUS:
parseNumber(source, tokens);
break;
default:
throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, ch);
}
ch = source.skipWhiteSpace();
switch(ch) {
case OBJECT_END_TOKEN:
if (source.getIndex() == tokenListIndex) {
throw new UnexpectedCharacterException("Parsing Value", "Key separator before value", source);
}
tokens.set(tokenListIndex, new Token(startIndex, source.getIndex(), TokenTypes.ATTRIBUTE_VALUE_TOKEN));
return true;
case OBJECT_ATTRIBUTE_SEP:
if (source.getIndex() == tokenListIndex) {
throw new UnexpectedCharacterException("Parsing Value", "Key separator before value", source);
}
tokens.set(tokenListIndex, new Token(startIndex, source.getIndex(), TokenTypes.ATTRIBUTE_VALUE_TOKEN));
return false;
default:
throw new UnexpectedCharacterException("Parsing Value", "Unexpected character", source, source.getCurrentChar());
}
}The parseValue method in the JsonFastParser class is responsible for parsing a JSON value from the provided source and populating the given tokens list with the parsed data.
Here is a step-by-step description of what the method does based on the given code:
-
Read the next character from the source while skipping any white space characters.
-
Get the current index of the source and the index of the
tokenslist. -
Insert a placeholder token at the current index in the
tokenslist. -
Use a switch statement to handle different types of characters:
- If the character is
{(indicating the start of an object), call theparseObjectmethod to parse the object. - If the character is
[(indicating the start of an array), call theparseArraymethod to parse the array. - If the character is
t(indicating the start of atrueboolean value), call theparseTruemethod to parse thetruevalue. - If the character is
f(indicating the start of afalseboolean value), call theparseFalsemethod to parse thefalsevalue. - If the character is
n(indicating the start of anullvalue), call theparseNullmethod to parse thenullvalue. - If the character is
"(indicating the start of a string), call theparseStringmethod to parse the string. - If the character is a digit (indicating the start of a number) or a minus or plus sign, call the
parseNumbermethod to parse the number. - If none of the above cases match, throw an
UnexpectedCharacterException.
- If the character is
-
Skip any remaining white space characters in the source.
-
Use another switch statement to handle different types of characters:
- If the character is
}(indicating the end of an object), check if the current index of the source is the same as the index of thetokenslist. If they are the same, throw anUnexpectedCharacterExceptionindicating that a key separator was found before a value. Otherwise, update the token at thetokenListIndexwith the start index and end index of the parsed value and returntrue. - If the character is
:(indicating a key separator), check if the current index of the source is the same as the index of thetokenslist. If they are the same, throw anUnexpectedCharacterExceptionindicating that a key separator was found before a value. Otherwise, update the token at thetokenListIndexwith the start index and end index of the parsed value and returnfalse. - If none of the above cases match, throw an
UnexpectedCharacterExceptionindicating that an unexpected character was found.
- If the character is
In summary, the parseValue method parses a JSON value from the source and updates the tokens list with the start and end indexes of the parsed value. It also checks for unexpected characters or incorrect placement of key separators before values.

private void parseObject(final CharSource source, TokenList tokens) {
final int startSourceIndex = source.getIndex();
final int tokenListIndex = tokens.getIndex();
tokens.placeHolder();
boolean done = false;
while (!done) {
done = parseKey(source, tokens);
if (!done)
done = parseValue(source, tokens);
}
source.next();
tokens.set(tokenListIndex, new Token(startSourceIndex, source.getIndex(), TokenTypes.OBJECT_TOKEN));
}The parseObject method in the JsonFastParser class is responsible for parsing a JSON object. Below is a step-by-step breakdown of what this method does based on its body:
-
The method starts by storing the current index of the input source and the index of the token list.
-
It creates a placeholder token in the token list to mark the starting point of the object.
-
It initiates a loop that continues until the parsing of the object is complete. The variable
doneis used as a flag to indicate if the parsing is done. -
Within the loop, the method calls the
parseKeymethod, passing the input source and token list. TheparseKeymethod is expected to parse the next key in the object and return a boolean value indicating whether the parsing is done. -
If the
parseKeymethod returnsfalse, indicating that the parsing of the key is not done, the method calls theparseValuemethod. TheparseValuemethod is responsible for parsing the corresponding value of the key and returns a boolean value indicating whether the parsing is done. -
The loop continues until either the
parseKeyorparseValuemethods indicate that the parsing is done. -
After the loop, the method calls
source.next()to move the input source to the next character. -
Finally, the method updates the token in the token list with the index range of the parsed object, using the
setmethod. The token is marked as an "OBJECT_TOKEN" to indicate that it represents a JSON object.
Note: The specific implementation details of the parseKey and parseValue methods are not provided in the given code snippet. These methods are likely responsible for parsing the key-value pairs within the JSON object.
- Java Open AI Client
- Using ChatGpt embeddings and hyde to improve search results
- Anthropics Claude Chatbot Gets Upgrade
- Elon Musks XAi new frontier for artificial intelligence
- Using Mockito to test JAI Java Open AI Client
- Fine tuning journey with Open AI API
- Using Open AI to create callback functions, the basis for plugins
- Using Java Open AI Client Async
- Fastest Java JSON Parser
- Java Open AI API Client on Github
- Medium: Introducing Java Open AI Client
- Medium: Using ChatGPT, Embeddings, and HyDE to Improve Search Results