JSON-java
JSON-java copied to clipboard
Suggestion: JSONArray#toList(class)
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 😄
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.
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).
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));
}
@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?
@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
@johnjaylward Should be updated now, thanks for catching this.
Closing this issue. Please post here if you disagree.