16

I have a list of Player objects getting passed into a JSP from a controller, and I want to display them in a couple of different ways on the same page:

  • a menu sorted by name
  • a list sorted by win/loss percentage

I could put separate sorted copies in the model, but dealing with different ways to display the same list seems more like a responsibility of the view, so I'd like to avoid putting the logic in the controller if I can. I already have a couple of classes implementing Comparator to help with the actual sorting.

What's the best way to do that in a JSP?

Can I sort the list before passing it in to the different forEach tags?

Mike Partridge
  • 5,128
  • 8
  • 35
  • 47
  • Have you considered just having one version of the list in the HTML/JS and letting the user's browser sort it according to their own wishes? I believe there's a jqueryui ability to do this fairly easily. – RHSeeger Jul 10 '11 at 03:30
  • I do need the list displayed in two places, but it might be a good idea to list Players and their stats in a table; in that case I would probably use displaytag. – Mike Partridge Jul 11 '11 at 04:54

3 Answers3

18

The SO EL Tag Wiki describes a way to do this without using a scriptlet: using an EL function to do the sort, then using the result for the items attribute in the JSTL core forEach tag.

The function class:

package org.hierax.ifdl.tags.player;

public final class PlayerSort {
    public static List<Player> sortByRank(List<Player> playerList) {
        Collections.sort(playerList, new PlayerSortByRank());
        return playerList;
    }

    public static List<Player> sortByAlias(List<Player> playerList) {
        Collections.sort(playerList, new PlayerSortByAlias());
        return playerList;
    }
}

The TLD:

<?xml version="1.0" encoding="UTF-8" ?>
<taglib 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

    <display-name>Player Functions</display-name>
    <tlib-version>1.0</tlib-version>
    <short-name>player</short-name>
    <uri>org.hierax.ifdl.tags</uri>

    <function>
        <name>sortByRank</name>
        <function-class>org.hierax.ifdl.tags.player.PlayerSort</function-class>
        <function-signature>java.util.List sortByRank(java.util.List)</function-signature>
    </function>

    <function>
        <name>sortByAlias</name>
        <function-class>org.hierax.ifdl.tags.player.PlayerSort</function-class>
        <function-signature>java.util.List sortByAlias(java.util.List)</function-signature>
    </function>

</taglib>

The menu JSP:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="p" uri="/WEB-INF/player.tld" %>

<h1>Players</h1>
<p>
    <c:forEach items="${p:sortByAlias(model.players)}" var="player">
        <a href="<c:url value="/player/${player.id}"/>" class="menuItem">${player.alias}</a>
    </c:forEach>
</p>
Community
  • 1
  • 1
Mike Partridge
  • 5,128
  • 8
  • 35
  • 47
  • related: regarding the Java comparison, I recommend the Apache Common's answer (Boris') of that question http://stackoverflow.com/questions/8036429/sorting-java-objects-using-multiple-keys – Adriano Jul 17 '13 at 09:23
  • 1
    Updated the link. Here's a copy made by BalusC: http://balusc.blogspot.com/2010/01/hidden-features-of-jspservlet.html – Mike Partridge Oct 09 '13 at 18:13
6

Employ Collections.sort(List, Comparator), providing your own Comparator as required to sort the list into the right order. The java, which could be embedded within <% and %> tags, would look something like:

List<Player> list = new ArrayList<Player>();
list.add(new Player()); // populate list
list.add(new Player()); // etc
Collections.sort(list, new Comparator<Player>() {
    public int compare(Player o1, Player o2)
    {
        return o1.getName().compareTo(o2.getName()); // Compare by name, for example
    }});

// Now iterations on list will be in 'name' order
for (Player player : list) {
    // Display player
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
1

I'd recommend having two sorted lists in the model. The lists will just contain object references, so it's not a big space issue, and I personally don't like doing that sort of work in the JSPs. If you presort them, it doesn't matter how many times the page is viewed in normal navigation, and as long as the lists don't change, you won't have to incur the sort overhead.

g051051
  • 1,021
  • 5
  • 11
  • Your arguments are good, but I'd like to keep display logic out of the controller unless there's a demonstrated performance reason to break that part of the pattern. – Mike Partridge Jul 10 '11 at 15:45
  • Consider it part of the model, not the controller. The model has two lists, backed by the same data, sorted in different ways. – g051051 Jul 11 '11 at 12:10
  • this means deep copying a list of your objects, no mean feat, or scanning the database twice ... – NimChimpsky Feb 13 '13 at 15:59
  • 1
    Why? Once you get the results back, you have a bunch of objects. Just add them all to another list and resort that list how you like. The objects are all the same. Why would you want to go back to the DB twice? – g051051 Feb 23 '13 at 17:44