1

I am building a web application using Java EE (although my problem is more Java based)

In a Servlet, I am getting a list of orders from the EJB. In this list of orders, there is a list of states for this order (sent, on dock, non received ...)

I want to sort this list of states by the date of the state. So I use Collections.sort like this:

    for (Command c : commands) {
        c.getStateList().sort(new Comparator<State>() {
                @Override
                public int compare(State o1, State o2) {
                    return o1.getStateDate().compareTo(o2.getStateDate());
                }
        });

        c.getStateList().sort(Collections.reverseOrder());
    }
request.setAttribute("commands", commands);

But when I display the results, the states are not sorted.

I tried to reverse the order as you can see, but it isn't working either.

As you can also see, I replaced the Collections.sort with the ListIWantToSort.sort. Still not working.

Any ideas on why it does not work or how I could repair it?

EDIT : Here is the getter for the list and its instanciation :

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "ciiCommande")
    private List<Etat> etatList;

    @XmlTransient
    public List<Etat> getEtatList() {
        return etatList;
    }

    List<Commande> commandes = new ArrayList<Commande>();

And I get my commands by a findAll Method.

To display them, I use that :

<c:forEach items="${commandes}" var="cmd">
    <td>${cmd.etatList[0].codeStatut.libelleSituation}</td>
</c:forEach>
  • What does `c.getEtatList()` return? –  May 29 '15 at 12:24
  • @LutzHorn it does return the states list taken by the order. –  May 29 '15 at 12:25
  • Does whatever is in `getEtatList()` implement the `Comparable` interface? – npinti May 29 '15 at 12:25
  • @trichetriche And what exacly is the *type* of this list? –  May 29 '15 at 12:26
  • Can you try to create [a MCVE](http://stackoverflow.com/help/mcve)? – assylias May 29 '15 at 12:27
  • 2
    Is `getEtatList()` returning a copy of the list inside `c`? If so, you are sorting the copy, which this then promptly discarded, and when you come to output/use `getEtatList()` again you get another, unsorted copy. – Paul May 29 '15 at 12:27
  • @npinti Using a thread on this website, [link](http://stackoverflow.com/questions/5927109/sort-objects-in-arraylist-by-date) I didn't implemented the Comparable interface –  May 29 '15 at 12:28
  • @LutzHorn this is a Etat List, Etat is a table in my database, which is an Entity class in my application –  May 29 '15 at 12:29
  • @Paul How do I know if this is a copy of the list ? I am learning Java EE and Java actually –  May 29 '15 at 12:30
  • @assylias it is Rather complicated to recreate an exemple, but if you want to try it, do a custom object, having a list of another custom object property, which have a date property. Then try to sort the list property –  May 29 '15 at 12:32
  • @trichetriche I don't know it is a copy. It also don't know it *isn't*. – Paul May 29 '15 at 12:34
  • @trichetriche the problem is that your example works as expected, so the problem is not in the description you have given so far. – assylias May 29 '15 at 12:43
  • @assylias well my example does work, it compiles fine. The problem is that, it doesn't sort the List how it should do. –  May 29 '15 at 12:44
  • @trichetriche see my answer - I'm doing exactly what your code is doing and the list gets sorted - the problem is somewhere else hence my comment above: try to recreate the issue with a minimal, complete example that reproduces the problem. – assylias May 29 '15 at 12:46
  • are you sure your compareTo method works fine? – user902383 May 29 '15 at 13:01
  • @user902383 I don't know, it's a compareTo I get from the Date type, it should work fine, don't it ? –  May 29 '15 at 13:03
  • @trichetriche If I were you, I would add some logging in (1) the method where you sort and (2) the getter and see what the list looks like at each point. It is possible that jsf calls the getter more than once and the returned list is "refetched" and not sorted. – assylias May 29 '15 at 13:05
  • Just to clarify - do you want to sort the commands, or the etatList? Plus, I see you are using Hibernate / JPA. is it possible the persistence framework is interfering with the ordering? And what does @XmlTransient do? – vikingsteve May 29 '15 at 14:28
  • I want to sort the etatList of each order, not sort the orders. Well, I don't think so, because I get the orders, then try to sort it, and I don't use the PU again. I don't know what @XmlTransient do, NetBeans put it (I used the GUI to create my entity classes) –  Jun 04 '15 at 06:25

6 Answers6

2

Try:

for (Commande c : commandes) {
                c.getEtatList().sort(Collections.reverseOrder(new Comparator<Etat>() {

                    @Override
                    public int compare(Etat o1, Etat o2) {
                        return o1.getDateEtat().compareTo(o2.getDateEtat());
                    }
                }));
            }

Since the sort method your using has been added to the List interface in Java SE 8, I guess you're using Java SE 8. Then you can rewrite it to the following:

commandes.foreach(c -> 
  c.getEtatList().sort(Comparator.comparing(Etat::getDateEtat).reversed());
);
Puce
  • 37,247
  • 13
  • 80
  • 152
  • There is no error, everything compiles fine. But in my application, instead of showing "Delivered" (which is supposed to be the last state), it shows "Not Delivered" (which is the previous one). FYI, I am getting the first result of the list to show this state. –  May 29 '15 at 12:41
  • there was some parenthesis errors in your second solution, but even after correcting it, it didn't work either. –  May 29 '15 at 12:47
  • @trichetriche what is the type of dateEtat and what are the possible values? – Puce May 29 '15 at 13:44
  • dateEtat is a Date, it can take all possibles values accorded to that type. But in my database, it goes from 01.05.2015 to 31.05.2015 –  May 29 '15 at 13:46
  • And what is the value of dateEtat in the case of "Not Delivered"? – Puce May 29 '15 at 13:48
  • its value is the moment when we knew the order wasn't delivered. –  Jun 04 '15 at 06:24
2

You are first sorting the list using the custom comparator. Then you are re-sorting it according to the reversed natural ordering of the elements - not the custom ordering you already applied. So the first sort is not taking effect as the list is re-ordered by the second sort. Note that Collections.reverseOrder() does not reverse the list - it is the reverse of the natural ordering (so the elements in getEtatList() must already be Comparable).

Try losing the second sort and doing:

c.getEtatList().sort(new Comparator<Etat>() {
    @Override
    public int compare(Etat o1, Etat o2) {
        // Note o2/o1 reversed.
        return o2.getDateEtat().compareTo(o1.getDateEtat());
    }
});
Paul
  • 3,009
  • 16
  • 33
  • the reverseOrder is actually another try, I didn't used it first. But But thank you for that piece of information, I'll remember that –  May 29 '15 at 12:34
  • What is returned by getDateEtat()? Is it a `java.util.Date`? – Paul May 29 '15 at 14:19
1

This should be what you need:

    Comparator<Etat> comparator = new Comparator<Etat>() {
        @Override
        public int compare(Etat o1, Etat o2) {
            return o1.getDateEtat().compareTo(o2.getDateEtat());
        }
    };

    for (Commande c : commandes) {
        Collections.sort(c.getEtatList(), comparator);
        // or this one: Collections.sort(c.getEtatList(), Collections.reverseOrder(comparator));
    }
vikingsteve
  • 38,481
  • 23
  • 112
  • 156
  • No sorry, not working either. (I also tried with the reverse order) –  May 29 '15 at 12:39
  • What is the actual type of `getStateList()` in `Command` class? One presume it is a `List`, or ? – vikingsteve May 29 '15 at 12:41
  • Yes, it is a `List` (State in french) : `private List etatList;` –  May 29 '15 at 12:42
  • and the `getEtatList()` method is just a getter, right? It doesn't copy the list? in fact can you paste the code for that method, and also where `etatList` is instiated via `new` ... – vikingsteve May 29 '15 at 12:53
  • And how are you displaying the commands list in the html page? if it is jsp, or how? Can you show the presentation code also. – vikingsteve May 29 '15 at 12:54
0

This works as expected, your problem is somewhere else:

public static void main(String[] args) {
  List<State> states = Arrays.asList(new State(2015, 1, 1),
                                     new State(2014, 1, 1),
                                     new State(2016, 1, 1));
  System.out.println(states); //not ordered
  states.sort(new Comparator<State>() {
    @Override public int compare(State o1, State o2) {
      return o1.getStateDate().compareTo(o2.getStateDate());
    }
  });
  System.out.println(states); //ordered
}

public static class State {
  private final LocalDate stateDate;
  public State(int year, int month, int day) {
    this.stateDate = LocalDate.of(year, month, day);
  }
  public LocalDate getStateDate() { return stateDate; }
  @Override public String toString() { return stateDate.toString(); }
}

Note that you seem to be using Java 8 and your comparator can be written:

states.sort(comparing(State::getStateDate));
assylias
  • 321,522
  • 82
  • 660
  • 783
  • Can you try with creating a new class called Command, having a list of States as a property ? Then you create a list of commands, and try to order every list of state –  May 29 '15 at 12:49
  • @trichetriche That won't make a difference, if one list can be sorted, several lists can be sorted too (unless you have messed up in the command class and are sharing a list or send a copy or .... - but I can't guess what you have done). You should read the link to MCVE I posted in an earlier comment and follow its recommendations. – assylias May 29 '15 at 12:53
  • my classes remain untouched since I got them as Entity Classes. And my code is very long, this is why I can't really focus on creating a good example. Maybe if I make a git repository ? –  May 29 '15 at 13:01
0

After days of struggle, I managed to find a solution.

The list isn't sorted after every attempt I made. I still don't know why.

But I found an annotation, @OrderBy, that sorts the list the way I want.

Thank you all for your help, maybe one day this problem will be sorted out (see the pun ? I am so funny).

Cheers

0

I appreciate your question, as I have just experienced this. I implemented 'Comparable' (as I have done many other times) on my JPA Entity class. When doing a Collections.sort on myMainJPA_Object.getMyList(), the overriden comparable method does not get invoked.

My work-around has been to create a new List as an ArrayList (for example), do a .addAll(myObject.getMyList()), then do Collections.sort on that new list, and then the sort works (my comparable method is invoked on the sort). For example:

List<ObjectsToSort> tempList = new ArrayList<>();
tempList.addAll(jpaEntity.getListOfStuff());
Collections.sort(tempList);
//Then you could set the list again
jpaEntity.setListOfStuff(tempList);

I really don't like this solution, but I don't know any other way around it, and haven't found anything about this problem (until your post). I liked your @OrderBy annotation suggestion, in my case though I need to re-sort again on a different method call, so this solution works for me.

Doug
  • 381
  • 3
  • 3