Java8 Collections.sort (sometimes) does not sort JPA returned lists

后端 未结 3 688
攒了一身酷
攒了一身酷 2020-11-28 12:24

Java8 keeps doing strange things in my JPA EclipseLink 2.5.2 environment. I had to delete the question https://stackoverflow.com/questions/26806183/java-8-sorting-behaviour

相关标签:
3条回答
  • 2020-11-28 12:39

    Wait for the bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=446236 to be fixed. Use the below dependency when it get's available or a snapshot.

    <dependency>
      <groupId>org.eclipse.persistence</groupId>
      <artifactId>eclipselink</artifactId>
      <version>2.6.0</version>
    </dependency>
    

    Until then use the workaround from the question:

    if (docs instanceof IndirectList) {
        IndirectList iList = (IndirectList)docs;
        Object sortTargetObject = iList.getDelegateObject();
        if (sortTargetObject instanceof List<?>) {
            List<Document> sortTarget=(List<Document>) sortTargetObject;
            Collections.sort(sortTarget,comparator);
        }
    } else {
        Collections.sort(docs,comparator);
    }
    

    or specify eager fetching where possible:

    // http://stackoverflow.com/questions/8301820/onetomany-relationship-is-not-working
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "parentFolder", fetch=FetchType.EAGER)
    
    0 讨论(0)
  • 2020-11-28 12:50

    The issue you are having is not with sort.

    TimSort is called via Arrays.sort which does the following:

    TimSort.sort(a, 0, a.length, c, null, 0, 0);
    

    So you can see the size of the array TimSort is getting is either 0 or 1.

    Arrays.sort is called from Collections.sort, which does the following.

    Object[] a = list.toArray();
    Arrays.sort(a, (Comparator)c);
    

    So the reason your collection is not getting sorted is that it is returning an empty array. So the collection that is being used is not conforming to the collections API by returning an empty array.

    You say you have a persistence layer. So it sounds like the problem is that the library you are using retrieves entities in a lazy way and does not populate its backing array unless it has to. Have a closer look at the collection you are trying to sort and see how it works. Your original unit test didn't show anything as it was not trying to sort the same collection that is used in production.

    0 讨论(0)
  • 2020-11-28 13:00

    Well, this is a perfect didactic play telling you why programmers shouldn’t extend classes not designed for being subclassed. Books like “Effective Java” tell you why: the attempt to intercept every method to alter its behavior will fail when the superclass evolves.

    Here, IndirectList extends Vector and overrides almost all methods to modify its behavior, a clear anti-pattern. Now, with Java 8 the base class has evolved.

    Since Java 8, interfaces can have default methods and so methods like sort were added which have the advantage that, unlike Collections.sort, implementations can override the method and provide an implementation more suitable to the particular interface implementation. Vector does this, for two reasons: now the contract that all methods are synchronized expands to sorting as well and the optimized implementation can pass its internal array to the Arrays.sort method skipping the copying operation known from previous implementations (ArrayList does the same).

    To get this benefit immediately even for existing code, Collections.sort has been retrofitted. It delegates to List.sort which will by default delegate to another method implementing the old behavior of copying via toArray and using TimSort. But if a List implementation overrides List.sort it will affect the behavior of Collections.sort as well.

                      interface method              using internal
                      List.sort                     array w/o copying
    Collections.sort ─────────────────> Vector.sort ─────────────────> Arrays.sort
    
    0 讨论(0)
提交回复
热议问题