Skip to content

io_nats_jparse_node

Rick Hightower edited this page Jul 18, 2023 · 1 revision

io.nats.jparse.node

class diagram

JsonTestUtils

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.

NullNode

The NullNode class represents a null value node in a tree structure. It is a concrete implementation of the ScalarNode interface.

@Override

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();
    }
}

Method: charAt

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.

Description

The charAt method returns the character at the specified index of the NullNode object.

Parameters

  • index (integer): The index of the character to retrieve.

Return Value

  • char: The character at the specified index.

Steps

  1. Start the method execution.
  2. Check the value of the index parameter using a switch statement.
  3. If index is 0, return the character 'n'.
  4. If index is 1, return the character 'u'.
  5. If index is 2 or 3, return the character 'l'.
  6. If none of the above cases match, throw an IllegalStateException.
  7. 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.

sequence diagram

NumberNode

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.

@Override

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:

  1. Check if the number node is an integer, by calling the method isInteger().
  2. If the number node is an integer, call the method intValue() to get the integer value and return it as an Object.
  3. If the number node is not an integer, check if it is a long integer, by calling the method isLong().
  4. If the number node is a long integer, call the method longValue() to get the long integer value and return it as an Object.
  5. 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 an Object.

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).

sequence diagram

@Override

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:

  1. The method overrides the charAt method defined in the CharSequence interface.

  2. It takes an int parameter called index, which represents the desired index of the character to be retrieved.

  3. The method first checks if the index is greater than the length of the source string.

  4. If the index is greater than the length of the source string, the method throws an ArrayIndexOutOfBoundsException with the provided index.

  5. If the index is valid (i.e., within the bounds of the source string), the method retrieves the character at the specified index.

  6. The character is obtained by calling the getChartAt method on the source object, passing the startIndex of the token plus the index as arguments.

  7. 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.

sequence diagram

@Override

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:

  1. The method is annotated with @Override, indicating that it overrides a method from the superclass or an interface. In this case, it overrides the subSequence method from the CharSequence interface.

  2. The method has two input parameters, start and end, which indicate the range of indices (inclusive) for the desired subsequence.

  3. The first line of the method's body checks if the end parameter is greater than the length of the character sequence. If it is, an IndexOutOfBoundsException is thrown.

  4. If the end parameter is within the valid range, the method proceeds to the next line.

  5. The method then calls the getCharSequence method on the source object with the calculated start and end indices. The start index is obtained by adding the start parameter to the startIndex of the token object, and the end index is obtained by adding the end parameter to the startIndex of the token object.

  6. Finally, the getCharSequence method returns the requested subsequence of characters.

That's the step-by-step description of the subSequence method in the NumberNode class.

sequence diagram

public boolean isInteger()

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:

  1. The method isInteger() takes no parameters and returns a boolean value indicating whether the number is an integer or not.

  2. The method starts by checking the value of the elementType variable, which is an enumeration representing the type of the number.

  3. If the elementType is INT, it means that the number is an integer.

  4. In the case when the elementType is INT, the isInteger() method calls the source.isInteger() method passing two parameters this.token.startIndex and this.token.endIndex. These parameters represent the start and end indices of the token associated with this number.

  5. 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.

  6. If the elementType is not INT, the method returns false, indicating that the number is not an integer.

  7. The isInteger() method provides a way to validate if the given number is an integer based on its type elementType.

sequence diagram

public boolean isLong()

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:

  1. The method is defined as a public boolean method, meaning it returns a boolean value and can be accessed from outside the class.

  2. The method starts with a switch statement that evaluates the value of the elementType variable. The elementType variable is presumably an enumeration or constant that represents the type of the element.

  3. Inside the switch statement, there is a case for the INT type. This means that if the elementType is equal to INT, the following code will be executed.

  4. Within the case INT, there is a return statement that calls a method isInteger() on the source object. This method is likely defined in another class or utility and takes two parameters: this.token.startIndex and this.token.endIndex. The purpose of this method is to check whether the token, which represents a portion of the input source, is an integer.

  5. The ! operator is applied to the result of the isInteger() method. This means that if the token is NOT an integer, the result will be true, indicating that the number is a long type.

  6. If the elementType is not equal to INT, the default case is executed. In this case, the method returns false, 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.

sequence diagram

StringNode

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).

RootNode

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.

@Override

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:

  1. The method is annotated with @Override, indicating that it overrides a method from a superclass or interface.

  2. The method returns a List<List<Token>>, which is a list of lists of Token objects.

  3. The method utilizes a switch statement based on the type of the rootToken variable.

  4. If the type of rootToken is OBJECT_TOKEN, the method calls the childrenTokens() method on the ObjectNode instance returned by the getObjectNode() method. The returned List<List<Token>> is then returned by the method.

  5. If the type of rootToken is ARRAY_TOKEN, the method calls the childrenTokens() method on the ArrayNode instance returned by the getArrayNode() method. The returned List<List<Token>> is then returned by the method.

  6. If the type of rootToken does not match any of the above cases, the method calls the doGetChildrenTokens() method. This method is not explicitly provided in the given snippet, but it is assumed to return a List<List<Token>>. The returned value is then returned by the childrenTokens() 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.

sequence diagram

ObjectNode

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.

@Override

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:

  1. The method is annotated with @Override, indicating that it overrides the implementation of the same method in a superclass or interface.

  2. The return type of the method is List<List<Token>>, which means it returns a list of lists of Token objects.

  3. Inside the method, there is an if statement to check if the childrenTokens variable is null. This variable is an instance variable of the ObjectNode class.

  4. If childrenTokens is null, the method proceeds to the next line. Otherwise, it skips to the return statement.

  5. On the next line, the method calls the getChildrenTokens() method from the NodeUtils class and passes the tokens parameter to it. The tokens parameter is an instance variable of the ObjectNode class.

  6. The return value from the getChildrenTokens() method is assigned to the childrenTokens variable.

  7. Finally, the method returns the value of the childrenTokens variable.

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.

sequence diagram

@Override

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:

  1. The entrySet method is marked with the @Override annotation, indicating that it is overriding a method from the superclass.

  2. 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 a CharSequence key and a Node value.

  3. Inside the AbstractSet constructor, 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.

  4. The contains method takes an object as a parameter and checks if the object node contains the specified entry. It delegates the check to the keys method, which returns a set of keys in the object node, and then calls the contains method of that set.

  5. The iterator method returns an iterator over the entries in the object node. It first obtains an iterator over the keys in the object node by calling the keys method. Then, it returns a new iterator object that implements the Iterator<Entry<CharSequence, Node>> interface. Each iteration, it converts the next key into a CharSequence and creates a new entry object with the key and the value obtained by calling the lookupElement method.

  6. The size method returns the number of entries in the object node. It delegates the size calculation to the keys method, which returns a set of keys in the object node, and then calls the size method 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.

sequence diagram

private Node lookupElement(final CharSequence key)

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;
}

Method lookupElement

The lookupElement method is defined in the ObjectNode class and is used to look up an element based on a given key.

Method Signature

private Node lookupElement(final CharSequence key)

Description

  1. Check if the elementMap attribute is null.

    • If it is null, create a new HashMap and assign it to elementMap.
  2. Retrieve the node associated with the given key from the elementMap.

    • Store the result in the node variable.
  3. 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.
  4. Retrieve the childrenTokens by calling the childrenTokens() method.

  5. Iterate over the childrenTokens list in increments of 2.

    • For each pair of tokens (item key and value):
      • Store the item key in the itemKey variable.
  6. Check if the item key matches the given key by calling the doesMatchKey method.

    • If it matches, proceed with the following steps.
    • If it does not match, move to the next pair of tokens.
  7. Call the createNodeForObject method from the NodeUtils class, passing the value tokens, source, and objectsKeysCanBeEncoded arguments.

    • Store the returned node in the node variable.
  8. Add the key and node pair to the elementMap.

    • This stores the key-value mapping for future lookups.
  9. Exit the loop.

  10. Return the node.

Return Value

The method returns the node associated with the given key.

sequence diagram

private boolean doesMatchKey(final List itemKey, final CharSequence 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;
}

Method: doesMatchKey

Description:

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.

Parameters:

  • itemKey (Type: List<Token>): A list of tokens representing the item key.
  • key (Type: CharSequence): The key to be checked for a match.

Steps:

  1. Get the token at index 1 from the itemKey list, and assign it to the keyToken variable.
  2. Check the type of the keyToken:
    • If the type is TokenTypes.STRING_TOKEN, proceed with the following steps:
      • Check if the length of keyToken is equal to the length of the key:
        • If not equal, return false.
      • Check if objectsKeysCanBeEncoded is true:
        • If true, execute the following sub-steps:
          • Create a new StringNode object named stringNode with the keyToken, source, and objectsKeysCanBeEncoded as parameters.
          • Convert the stringNode to a String and assign it to the string variable.
          • Iterate over each character in the key using a for loop:
            • Compare the character at the current index in the string with the character at the current index in the key:
              • If they are not equal, return false.
          • If all characters match, return true.
        • If false, execute the following sub-step:
          • Call the matchChars method on the source object, passing keyToken.startIndex, keyToken.endIndex, and key as parameters.
          • Return the result of the matchChars method.
    • If the type is not TokenTypes.STRING_TOKEN, return false.

Return Value:

  • Type: boolean
  • If the key matches the specified item key, true is returned. Otherwise, false is returned.

sequence diagram

private List keys()

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:

  1. Check if the keys list is null.
  2. If the keys list is null, retrieve the children tokens of the object and store them in the childrenTokens list.
  3. Create a new ArrayList with an initial capacity equal to half of the size of the childrenTokens list, and assign it to the keys list.
  4. Use a for loop to iterate over the childrenTokens list, incrementing the index by 2 each iteration.
  5. Inside the loop, retrieve the itemKey list at the current index from the childrenTokens list.
  6. Get the second token from the itemKey list and assign it to the keyToken variable.
  7. Use a switch statement to check the type of the keyToken.
  8. If the type of the keyToken is STRING_TOKEN, create a new StringNode object using the keyToken, source, and objectsKeysCanBeEncoded variables.
  9. Add the StringNode object to the keys list.
  10. If the type of the keyToken is not STRING_TOKEN, throw an IllegalStateException with a message indicating that only strings are allowed for keys.
  11. After the loop ends, return the keys list.

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.

sequence diagram

ArrayNode

The ArrayNode class represents an array node in a tree structure. It extends the AbstractList class and implements the CollectionNode interface.

@Override

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:

  1. The method overrides the childrenTokens method from the superclass (Node), indicating that it provides a specific implementation for this method.

  2. The method has a return type of List<List<Token>>, which means it returns a list of lists of Token objects.

  3. When the method is invoked, it first checks if the variable childrenTokens is null.

  4. If childrenTokens is null, it means that the list of children tokens has not been initialized yet.

  5. In that case, the method invokes the static getChildrenTokens method from the NodeUtils class, passing the tokens list as an argument.

  6. The getChildrenTokens method is responsible for extracting and organizing the tokens that represent the children of the current node. It likely iterates over the tokens list, identifies the children tokens, and creates a nested list structure to represent the children tokens of each child node.

  7. After getChildrenTokens returns, the method assigns the returned value to the childrenTokens variable, effectively caching the list of children tokens for future invocations.

  8. Finally, the method returns the value of the childrenTokens variable, which now contains the list of children tokens for the current ArrayNode.

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()

Node[] elements() {
    if (elements == null) {
        elements = new Node[childrenTokens().size()];
    }
    return elements;
}

Method Description: 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.

Steps:

  1. Check if the elements array is null.
  2. If the elements array is null, create a new array of Node objects with the size equal to the number of children tokens of the ArrayNode object. This ensures that the elements array is properly initialized with the correct size.
  3. Return the elements array.

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.

sequence diagram

public List map(Function<Node, ? extends R> mapper)

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:

  1. It takes a Function object called mapper as a parameter. The mapper function is used to transform each element of the array.

  2. It creates an ArrayList object called list with an initial capacity equal to the size of the array. This is done to optimize the performance by reducing the number of reallocations.

  3. It retrieves an array of Node objects called elements from the elements() method.

  4. It iterates over each element in the elements array using a for loop.

  5. Within the loop, it retrieves the current element at index i and assigns it to a variable called element. If the element is null, it calls the getNodeAt method to fetch the element at index i and assigns it back to element. This is done to ensure that each element is not null before applying the mapper function.

  6. It applies the mapper function to the element using the apply method, and adds the transformed result to the list using the add method.

  7. After processing all the elements, it returns the list containing 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.

sequence diagram

public Optional findObjectNode(Predicate predicate)

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);
}

findObjectNode(Predicate<ObjectNode> predicate)

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:

  1. Get array elements: Retrieve the array elements using the elements() method, which returns an array of Node objects.

  2. Iterate over array elements: Iterate over each element in the array using a standard for loop.

  3. Handle null elements: Check if the current array element is null. If so, call the getNodeAt(i) method to retrieve the element at the given index.

  4. Check element type: Determine if the current element is of type OBJECT. This is done by calling the type() method on the Node object and comparing the result with NodeType.OBJECT.

  5. Convert element to ObjectNode: If the element is an OBJECT type, it is converted to an ObjectNode by calling the asCollection().asObject() method.

  6. Test ObjectNode with the predicate: Apply the given predicate to the ObjectNode using the test() method. If the test condition is satisfied, the ObjectNode is considered a match.

  7. Set matched ObjectNode: If a match is found, assign the matched ObjectNode to the node variable and exit the loop.

  8. Return Optional<ObjectNode>: Wrap the matched ObjectNode in an Optional object and return it. If no match was found, null is returned as an Optional by using Optional.ofNullable().

Note: The method stops once a matching ObjectNode is found and returns it immediately, without iterating over the remaining array elements.

sequence diagram

public Optional find(Predicate predicate)

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);
}

find Method

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.

Method Signature

public Optional<Node> find(Predicate<Node> predicate)

Method Description

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.

Parameters

  • predicate: A Predicate<Node> used to test each element of the array. It is a functional interface that defines a single abstract method test which takes a Node and returns a boolean indicating whether the given node matches the required criteria.

Local Variables

  • elements: An array of Node elements obtained from the elements method of the ArrayNode class.
  • node: A Node variable used to store the matching element. It is initialized as null and later assigned the matching element if found.

Loop

The method uses a for loop to iterate through the elements of the array.

  1. It initializes the loop counter i to 0.
  2. The loop runs as long as i is less than the length of the elements array.
  3. In each iteration, the current element at index i is assigned to the element variable.
  4. If the element is null, the getNodeAt method is called to obtain the element at index i.
  5. The test method of the predicate is called with the element as input. If it returns true, the node variable is assigned the value of element and the loop is exited using the break statement.
  6. After the loop, the method returns an Optional containing the value of node.

Return Value

The method returns an Optional<Node>, which may contain the matching Node if found, or an empty Optional if no matching node was found.

sequence diagram

public List filterObjects(Predicate predicate)

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:

  1. The method takes in a Predicate<ObjectNode> as a parameter, which allows the caller to specify a condition for filtering the objects.

  2. It retrieves the elements of the array that the ArrayNode represents by calling the elements() method.

  3. It initializes a list called arrayList to store the filtered object nodes. The initial capacity of the ArrayList is set to length / 2, where length is the length of the elements array.

  4. It then iterates over each element in the array using a for loop.

  5. 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.

  6. It then checks the type of the element using the type() method. If the type is NodeType.OBJECT, it proceeds with the following steps.

  7. It converts the element to an ObjectNode by calling the asCollection().asObject() method.

  8. It applies the predicate to the ObjectNode by calling the test(objectNode) method on the predicate. If the predicate returns true, the ObjectNode is added to the arrayList using the add(objectNode) method.

  9. After the loop ends, the method returns the arrayList containing the filtered ObjectNode objects.

This method allows you to filter an array of objects and receive a list of object nodes that satisfy the specified predicate.

sequence diagram

public List filter(Predicate 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:

  1. Declare a local variable elements and assign the result of the elements() method call. This method returns an array of Node objects.

  2. Get the length of the elements array and store it in a variable called length.

  3. Create a new ArrayList called arrayList with an initial capacity of length / 2.

  4. Start a loop that iterates over the elements of the elements array. The loop index is i, initialized to 0.

  5. Get the Node object at index i and assign it to a local variable called element. If the element is null, call the getNodeAt(i) method to retrieve a non-null element.

  6. Check if the element satisfies the given predicate. The predicate is passed as a parameter to the filter method and is of type Predicate<Node>. The test method of the Predicate interface is used to evaluate the element against the given predicate.

  7. If the element passes the predicate test, add it to the arrayList using the add method.

  8. Continue the loop until all elements in the elements array have been processed.

  9. Return the arrayList containing the elements that passed the predicate test.

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.

sequence diagram

BooleanNode

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.

@Override

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();
        }
    }
}

Method charAt in class io.nats.jparse.node.BooleanNode

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.

Method Signature

public char charAt(int index) 

Method Body

@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.

sequence diagram

Clone this wiki locally