Skip to content

Suggestion: JSONArray#toList(class) #674

Closed

Description

@Chew

The current JSONArray#toList() converts the array to a list of Object. This makes things a little tough to work with.

When, for example, you have a list of typically JSON Objects or Strings, you have to do something like this:

jarr.toList().stream().map(Object::toString).toList(); // List of string
jarr.toList().stream().map(o -> (JSONObject) o).toList(); // List of JSONObject

I wrote a function that implments this, but I'm not too Java experty to know if it's ideal:

    /**
     * Converts a JSONArray to a list of {@code <T>}.
     *
     * @param array The JSONArray
     * @param cast The class to cast to
     * @param <T> The type to cast to
     * @return A list of {@code <T>}
     */
    public static <T> List<T> toList(JSONArray array, Class<T> cast) {
        List<T> results = new ArrayList<>(array.length());
        for (Object element : array) {
            if (element == null || JSONObject.NULL.equals(element)) {
                results.add(null);
            } else {
                results.add(cast.cast(element));
            }
        }
        return results;
    }

It's a little messy but it essentially casts each item in the array to the specific object. This is of course missing any exception handling since ClassCastException is likely.

Am I going about my suggestion all wrong? Is there already a way to do this? Please let me know 😄

Activity

  1. johnjaylward commented on Mar 21, 2022

    @johnjaylward
    Contributor

    I think your function is the right idea, but not quite there. I'd implement this similar to what you have, but more like this:

     /**
         * Converts a JSONArray to a list of {@code <T>}.
         *
         * @param array The JSONArray
         * @param cast The class to cast to
         * @param ignoreInvalid when true, items that can't be cast are not added to the result array as null. If false, items that can't be cast will be inserted as null. Values that are null before casting will be kept as null in the result array.
         * @param <T> The type to cast to
         * @return A list of {@code <T>}
         */
        public static <T> List<T> toList(JSONArray array, Class<T> cast, boolean ignoreInvalid) {
            List<T> results;
            if(ignoreInvalid) results = new ArrayList<>();
            else results = new ArrayList<>(array.length());
            for (Object element : array) {
                if (JSONObject.NULL.equals(element)) {
                    results.add(null);
                } else if(cast.isAssignableFrom(element.getClass()) {
                    results.add(cast.cast(element));
                } else if(!ignoreInvalid) {
                    results.add(null);
                }
            }
            return results;
        }

    using isAssignableFrom prevents any need for exception handling, and trimming out unwanted items from the result array that don't cast can save time on processing the result in downstream processors.

  2. johnjaylward commented on Mar 21, 2022

    @johnjaylward
    Contributor

    personally, I wouldn't bother with toList at all in your use-case though. as in #672, I would just use the spliterator to get a stream and continue to use the Map option like you do:

    java.util.StreamSupport(jarr.spliterator(), false)
        .filter(Objects::nonNull)
        .filter(i-> JSONObject.class.isAssignableFrom(i.getClass())
        .map(i-> (JSONObject)i)
      // process
    ;

    Using toList defeats the purpose of using a stream in the first place which is to prevent creation of extra object (in this case an entire array).

  3. johnjaylward commented on Mar 21, 2022

    @johnjaylward
    Contributor

    if you want to make that as a helper method, it would look something like this:

    public static <T> Stream<T> toStream(JSONArray array, Class<T> cast) {
        return java.util.StreamSupport(jarr.spliterator(), false)
            .filter(Objects::nonNull)
            .filter(i-> cast.isAssignableFrom(i.getClass())
            .map(i-> cast.cast(i));
    }
  4. stleary commented on Mar 22, 2022

    @stleary
    Owner

    @Chew No objections if you would like to submit a pull request. Please make sure the code either handles exceptions or has a language supported workaround. Keep in mind the project's Java version requirement: What version of Java does this project require?

  5. johnjaylward commented on Sep 5, 2023

    @johnjaylward
    Contributor

    @stleary , looks like the wiki needs a quick update to note the move to Java8 : https://github.com/stleary/JSON-java/wiki/FAQ#what-version-of-java-does-this-project-require

  6. stleary commented on Sep 5, 2023

    @stleary
    Owner

    @johnjaylward Should be updated now, thanks for catching this.

  7. stleary commented on Sep 30, 2023

    @stleary
    Owner

    Closing this issue. Please post here if you disagree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions