Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: WEB MVC
    • Labels:
      None

      Description

      Today´s in most production ready web applications users expect to be able to sort displayed data, currently roo´s generated listings don´t allow for sorting.

      So entities should be made comparable with a estandard generated compareTo method like the actual toString method generated by roo, this way in the listings it would be easy to costomize general sorting of entities.

      Also the UI should be able to allow sorting by field, like many Ui frameworks support out of the box.

        Activity

        Hide
        Alexander Heusingfeld added a comment -

        Hi

        there is quite a quick fix for this issue. There is a very small javascript file which can be found here http://www.kryogenix.org/code/browser/sorttable/
        All you have to do is
        1. download the script and put it into /src/main/webapp/sorttable.js
        2. add the javascript to the header.jsp like the following <script type="text/javascript" src="<c:url value="/static/sorttable.js"/>"> </script>
        3. add the attribute class="sortable" to every table you like to have sortable

        Works like a charm.

        @Ben this is licensed unter X11, I'm too sure but I think this might even allow bundling with ROO? What do you think?

        Show
        Alexander Heusingfeld added a comment - Hi there is quite a quick fix for this issue. There is a very small javascript file which can be found here http://www.kryogenix.org/code/browser/sorttable/ All you have to do is 1. download the script and put it into /src/main/webapp/sorttable.js 2. add the javascript to the header.jsp like the following <script type="text/javascript" src="<c:url value="/static/sorttable.js"/>"> </script> 3. add the attribute class="sortable" to every table you like to have sortable Works like a charm. @Ben this is licensed unter X11, I'm too sure but I think this might even allow bundling with ROO? What do you think?
        Hide
        Raúl Arabaolaza added a comment -

        While it would be very quick i see some problems with this approach
        1. Java developers don´t have much control about sorting process, my opinion is that sorting entities should be done by using Comparable methods in server side
        2. It creates a dependency to a concrete script instead of using Spring JS to decouple from concrete javascript libraries
        3. Don´t male entities Comparable

        Just an opinion.

        What i would like to implement as long as the templating code in mvc addon and the addon apis become stable enough is something like:

        1. Create a Comparable addon that will mark all my entities as Comparable and generate a field based comparator to allow sorting by field in server side by using a RooComparable annotation
        2. Add a new method to the generated controller to sort the entities list by using the generated Comparator
        3. Use Spring JS to add an AjaxEventDecorator to headers wich will triger the sort request

        Regards, Raúl

        Show
        Raúl Arabaolaza added a comment - While it would be very quick i see some problems with this approach 1. Java developers don´t have much control about sorting process, my opinion is that sorting entities should be done by using Comparable methods in server side 2. It creates a dependency to a concrete script instead of using Spring JS to decouple from concrete javascript libraries 3. Don´t male entities Comparable Just an opinion. What i would like to implement as long as the templating code in mvc addon and the addon apis become stable enough is something like: 1. Create a Comparable addon that will mark all my entities as Comparable and generate a field based comparator to allow sorting by field in server side by using a RooComparable annotation 2. Add a new method to the generated controller to sort the entities list by using the generated Comparator 3. Use Spring JS to add an AjaxEventDecorator to headers wich will triger the sort request Regards, Raúl
        Hide
        Raúl Arabaolaza added a comment -

        Hi,

        I´ve develop the sort functionality at a basic level, it can be extended if you people think my aproach is worth the work.

        First of all, i have created a new addon, called comparator, that will generate a comparator for every formBackingObject defined in the web scaffold annotation.

        This generator will sort based on a field name, if the field is comparable it will use the compareTo method of the field, if not the field will be converted to string (using the toString method) and the resulting strings will be compared, here´s an example from a generated itd.

        privileged aspect ChoiceComparator_Roo_Comparator {

        declare parents: ChoiceComparator implements Comparator;

        private java.lang.String ChoiceComparator.field = new java.lang.String();

        public ChoiceComparator.new(String field)

        { super(); this.field = field; }

        public int ChoiceComparator.compare(Object instance1, Object instance2) {
        try {
        Class comparableClass=Comparable.class;
        Object value1=org.apache.commons.beanutils.PropertyUtils.getProperty(instance1, field);
        Object value2=org.apache.commons.beanutils.PropertyUtils.getProperty(instance2, field);
        if(comparableClass.isInstance(value1))

        { return ((Comparable)value1).compareTo(value2); }

        else

        { return value1.toString().compareTo(value2.toString()); }


        } catch (IllegalAccessException e)

        { throw new IllegalArgumentException("Unable to access property "+field+" accesor method",e); }

        catch (java.lang.reflect.InvocationTargetException e)

        { throw new IllegalArgumentException("Unable to execute accesor method for property "+field,e); }

        catch (NoSuchMethodException e)

        { throw new IllegalArgumentException("Unable to find accesor method for property "+field,e); }


        }

        }

        This way i don´t need to generate a full fledged compareTo method wich can be dificult to implement as Ben said in the forum, and is compatible with all the JDK classes. if user wants to customize the sort for complex types (sorting by entities) he only needs to manually add the comparable interface to the entity, of course he also can modify the generated comparator or even the generated sort method.

        Comparator creation will be trigerred by the webscaffold metadata when sort is not in the disallowedOperations (I´ve modify the annotations to add this value), also it will generate a controller method named sort.

        Now the generated JSP will include as headers links to the sort method, again only if sort is not disallowed, and the propper springjavascript ajax decorators for that links.

        Possible improvements include a cache mechanism for comparators (we don´t need to create more than one for field) and the ability to indicate a comparator to use insted of the generated one.

        Feel free to contact me at raul.arabaolaza@gmail.com for futher details.

        Path is attached, hope the patch is correctly generated, i´m not very used to create patches

        Best Regards, Raúl

        Show
        Raúl Arabaolaza added a comment - Hi, I´ve develop the sort functionality at a basic level, it can be extended if you people think my aproach is worth the work. First of all, i have created a new addon, called comparator, that will generate a comparator for every formBackingObject defined in the web scaffold annotation. This generator will sort based on a field name, if the field is comparable it will use the compareTo method of the field, if not the field will be converted to string (using the toString method) and the resulting strings will be compared, here´s an example from a generated itd. privileged aspect ChoiceComparator_Roo_Comparator { declare parents: ChoiceComparator implements Comparator; private java.lang.String ChoiceComparator.field = new java.lang.String(); public ChoiceComparator.new(String field) { super(); this.field = field; } public int ChoiceComparator.compare(Object instance1, Object instance2) { try { Class comparableClass=Comparable.class; Object value1=org.apache.commons.beanutils.PropertyUtils.getProperty(instance1, field); Object value2=org.apache.commons.beanutils.PropertyUtils.getProperty(instance2, field); if(comparableClass.isInstance(value1)) { return ((Comparable)value1).compareTo(value2); } else { return value1.toString().compareTo(value2.toString()); } } catch (IllegalAccessException e) { throw new IllegalArgumentException("Unable to access property "+field+" accesor method",e); } catch (java.lang.reflect.InvocationTargetException e) { throw new IllegalArgumentException("Unable to execute accesor method for property "+field,e); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Unable to find accesor method for property "+field,e); } } } This way i don´t need to generate a full fledged compareTo method wich can be dificult to implement as Ben said in the forum, and is compatible with all the JDK classes. if user wants to customize the sort for complex types (sorting by entities) he only needs to manually add the comparable interface to the entity, of course he also can modify the generated comparator or even the generated sort method. Comparator creation will be trigerred by the webscaffold metadata when sort is not in the disallowedOperations (I´ve modify the annotations to add this value), also it will generate a controller method named sort. Now the generated JSP will include as headers links to the sort method, again only if sort is not disallowed, and the propper springjavascript ajax decorators for that links. Possible improvements include a cache mechanism for comparators (we don´t need to create more than one for field) and the ability to indicate a comparator to use insted of the generated one. Feel free to contact me at raul.arabaolaza@gmail.com for futher details. Path is attached, hope the patch is correctly generated, i´m not very used to create patches Best Regards, Raúl
        Hide
        Shahzada Hatim added a comment -

        I think there should be a common sort/filter/search plugin which can generate CRUD for all kinds of sorting. Such plugin could give a considerable boost to CRUD based apps.

        Show
        Shahzada Hatim added a comment - I think there should be a common sort/filter/search plugin which can generate CRUD for all kinds of sorting. Such plugin could give a considerable boost to CRUD based apps.
        Hide
        Harald Walker added a comment -

        Agree, that lists in default views should be sortable as option per column but sorting should happen in the database.

        Show
        Harald Walker added a comment - Agree, that lists in default views should be sortable as option per column but sorting should happen in the database.
        Hide
        Domingo Gómez García added a comment -

        I think the best approach is to refine a bit generated X_Roo_Entity.aj and X_Roo_Finder.aj with this change:

        //Sample using my congress manager application

        public static TypedQuery<Congress> Congress.findCongressesByOpeningBetween(Date minOpening, Date maxOpening)

        { if (minOpening == null) throw new IllegalArgumentException("The minOpening argument is required"); if (maxOpening == null) throw new IllegalArgumentException("The maxOpening argument is required"); EntityManager em = Congress.entityManager(); TypedQuery<Congress> q = em.createQuery("SELECT o FROM Congress AS o WHERE o.opening BETWEEN :minOpening AND :maxOpening", Congress.class); q.setParameter("minOpening", minOpening); q.setParameter("maxOpening", maxOpening); return q; }

        To:
        public static TypedQuery<Congress> Congress.findCongressesByOpeningBetween(Date minOpening, Date maxOpening, String sortField, boolean orderAsc)

        { if (sortField== null) throw new IllegalArgumentException("The sorting field argument is required"); if (minOpening == null) throw new IllegalArgumentException("The minOpening argument is required"); if (maxOpening == null) throw new IllegalArgumentException("The maxOpening argument is required"); EntityManager em = Congress.entityManager(); TypedQuery<Congress> q = em.createQuery("SELECT o FROM Congress AS o WHERE o.opening BETWEEN :minOpening AND :maxOpening ORDER BY o."+sortField+" "+(orderAsc?"ASC":"DESC"), Congress.class); q.setParameter("minOpening", minOpening); q.setParameter("maxOpening", maxOpening); return q; }

        I don't know if's possible for a compiled query to use parameters for sorting instead of raw string concatenation like I did.
        I'd like to see that changes included in roo by command option (maybe --sorting=true).

        Regards.

        Show
        Domingo Gómez García added a comment - I think the best approach is to refine a bit generated X_Roo_Entity.aj and X_Roo_Finder.aj with this change: //Sample using my congress manager application public static TypedQuery<Congress> Congress.findCongressesByOpeningBetween(Date minOpening, Date maxOpening) { if (minOpening == null) throw new IllegalArgumentException("The minOpening argument is required"); if (maxOpening == null) throw new IllegalArgumentException("The maxOpening argument is required"); EntityManager em = Congress.entityManager(); TypedQuery<Congress> q = em.createQuery("SELECT o FROM Congress AS o WHERE o.opening BETWEEN :minOpening AND :maxOpening", Congress.class); q.setParameter("minOpening", minOpening); q.setParameter("maxOpening", maxOpening); return q; } To: public static TypedQuery<Congress> Congress.findCongressesByOpeningBetween(Date minOpening, Date maxOpening, String sortField, boolean orderAsc) { if (sortField== null) throw new IllegalArgumentException("The sorting field argument is required"); if (minOpening == null) throw new IllegalArgumentException("The minOpening argument is required"); if (maxOpening == null) throw new IllegalArgumentException("The maxOpening argument is required"); EntityManager em = Congress.entityManager(); TypedQuery<Congress> q = em.createQuery("SELECT o FROM Congress AS o WHERE o.opening BETWEEN :minOpening AND :maxOpening ORDER BY o."+sortField+" "+(orderAsc?"ASC":"DESC"), Congress.class); q.setParameter("minOpening", minOpening); q.setParameter("maxOpening", maxOpening); return q; } I don't know if's possible for a compiled query to use parameters for sorting instead of raw string concatenation like I did. I'd like to see that changes included in roo by command option (maybe --sorting=true). Regards.
        Hide
        Domingo Gómez García added a comment -

        (Please delete previous comment without code format).
        I think the best approach is to refine a bit generated X_Roo_Entity.aj and X_Roo_Finder.aj with this change:

        Congress_Roo_Entity.aj
        //Sample using my congress manager application
        
        public static TypedQuery<Congress> Congress.findCongressesByOpeningBetween(Date minOpening, Date maxOpening) {
          if (minOpening == null) throw new IllegalArgumentException("The minOpening argument is required");
          if (maxOpening == null) throw new IllegalArgumentException("The maxOpening argument is required");
          EntityManager em = Congress.entityManager();
          TypedQuery<Congress> q = em.createQuery("SELECT o FROM Congress AS o WHERE o.opening BETWEEN :minOpening AND :maxOpening", Congress.class);
          q.setParameter("minOpening", minOpening); q.setParameter("maxOpening", maxOpening);
          return q;
         }
        

        To:

        Congress_Roo_Entity
        public static TypedQuery<Congress> Congress.findCongressesByOpeningBetween(Date minOpening, Date maxOpening, String sortField, boolean orderAsc) { 
          if (sortField== null) throw new IllegalArgumentException("The sorting field argument is required");
          if (minOpening == null) throw new IllegalArgumentException("The minOpening argument is required");
          if (maxOpening == null) throw new IllegalArgumentException("The maxOpening argument is required");
          EntityManager em = Congress.entityManager();
          TypedQuery<Congress> q = em.createQuery("SELECT o FROM Congress AS o WHERE o.opening BETWEEN :minOpening AND :maxOpening ORDER BY o."+sortField+" "+(orderAsc?"ASC":"DESC"), Congress.class);
          q.setParameter("minOpening", minOpening);
          q.setParameter("maxOpening", maxOpening); 
          return q; 
        }
        

        I don't know if's possible for a compiled query to use parameters for sorting instead of raw string concatenation like I did.
        I'd like to see that changes included in roo by command option (maybe --sorting=true).

        Regards.

        Show
        Domingo Gómez García added a comment - (Please delete previous comment without code format). I think the best approach is to refine a bit generated X_Roo_Entity.aj and X_Roo_Finder.aj with this change: Congress_Roo_Entity.aj //Sample using my congress manager application public static TypedQuery<Congress> Congress.findCongressesByOpeningBetween(Date minOpening, Date maxOpening) { if (minOpening == null ) throw new IllegalArgumentException( "The minOpening argument is required" ); if (maxOpening == null ) throw new IllegalArgumentException( "The maxOpening argument is required" ); EntityManager em = Congress.entityManager(); TypedQuery<Congress> q = em.createQuery( "SELECT o FROM Congress AS o WHERE o.opening BETWEEN :minOpening AND :maxOpening" , Congress.class); q.setParameter( "minOpening" , minOpening); q.setParameter( "maxOpening" , maxOpening); return q; } To: Congress_Roo_Entity public static TypedQuery<Congress> Congress.findCongressesByOpeningBetween(Date minOpening, Date maxOpening, String sortField, boolean orderAsc) { if (sortField== null ) throw new IllegalArgumentException( "The sorting field argument is required" ); if (minOpening == null ) throw new IllegalArgumentException( "The minOpening argument is required" ); if (maxOpening == null ) throw new IllegalArgumentException( "The maxOpening argument is required" ); EntityManager em = Congress.entityManager(); TypedQuery<Congress> q = em.createQuery( "SELECT o FROM Congress AS o WHERE o.opening BETWEEN :minOpening AND :maxOpening ORDER BY o." +sortField+ " " +(orderAsc? "ASC" : "DESC" ), Congress.class); q.setParameter( "minOpening" , minOpening); q.setParameter( "maxOpening" , maxOpening); return q; } I don't know if's possible for a compiled query to use parameters for sorting instead of raw string concatenation like I did. I'd like to see that changes included in roo by command option (maybe --sorting=true). Regards.
        Hide
        Basil Vandegriend added a comment -

        This appears related to ROO-241 and ROO-3148.

        Show
        Basil Vandegriend added a comment - This appears related to ROO-241 and ROO-3148 .

          People

          • Assignee:
            Rossen Stoyanchev
            Reporter:
            Raúl Arabaolaza
          • Votes:
            52 Vote for this issue
            Watchers:
            24 Start watching this issue

            Dates

            • Created:
              Updated: