Search code examples
javamongodbcastingclasscastexceptionmongo-java-driver

java.lang.ClassCastException on collect() of ArrayList<Document>


I am trying to search through a mongo database to find a user given search term in one of the fields:

    @GetMapping(value = {"/classes/search/{term}"})
    public String className (
        @PathVariable(required = true, value = "term") String term
    ) throws Exception {
        // Escape user input
        final String filteredTerm = escapeUserInput(term);

        // Match using Bson filter
        ArrayList<Document> matchedClasses = new ArrayList<Document>();
        for (String modName : DATABASE.listCollectionNames()) {
            ArrayList<Document> filteredContents = new ArrayList<Document>();
            try {
                getCollection(modName).find(
                    Filters.or(
                        Filters.text(filteredTerm),
                        Filters.eq("count", Long.parseLong(filteredTerm))
                    )
                ).into(filteredContents);
            } catch (NumberFormatException e) {
                getCollection(modName).find(Filters.text(filteredTerm)).into(filteredContents);
            }

            // Add to final doc if match is found
            if (filteredContents != null) {
                matchedClasses.addAll(filteredContents);
            }
        }

        return String.valueOf(matchedClasses
            .stream()
            .distinct()
            .sorted()
            .collect(Collectors.toList())
        );

    }

}

All getCollection() does is retrieve the mongo collection.

When passing any search term that SUCCESSFULLY matches something in the database, I get a ClassCastException supposedly on Line 140 (.collect(Collectors.toList()))

java.lang.ClassCastException: class org.bson.Document cannot be cast to class java.lang.Comparable (org.bson.Document is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
    at java.base/java.util.Comparators$NaturalOrderComparator.compare(Comparators.java:47) ~[na:na]
    at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) ~[na:na]
    at java.base/java.util.TimSort.sort(TimSort.java:220) ~[na:na]
    at java.base/java.util.Arrays.sort(Arrays.java:1515) ~[na:na]
    at java.base/java.util.ArrayList.sort(ArrayList.java:1750) ~[na:na]
    at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:392) ~[na:na]
    at java.base/java.util.stream.DistinctOps$1$2.end(DistinctOps.java:168) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[na:na]
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[na:na]
    at com.api.main.Executer.className(Executer.java:140) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
<TRUNCATED>

I suspect it's something to do with Filters.text as that is what I changed which has started to cause this error but I don't understand why and where my next step from here would be?


Solution

  • matchedClasses is an ArrayList<Document> and Document does not implement Comparable.

    When running .collect(Collectors.toList()), it also tries to sort the Stream elements because you called sorted. Bot for sorting, the elements need to either implement Comparable or pass a Comparator to .sorted().

    As Document is a MongoDB class that you cannot control, you need to pass a Compatator to .sorted():

    //...
    .sorted((document1,document2)->/*compare documents here*/)
    //...