Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Column sort for index crashes on fields containing multiple values #310

Open
monetschemist opened this issue Sep 14, 2020 · 2 comments
Open

Comments

@monetschemist
Copy link

I'm having a hard time describing this, but basically in the index view on any table in my project, if I click on the column heading to sort fields, things work fine, except when I click on a column whose elements are many-to-many; that generates a crash.

I'm at the very earliest stages in the application, just prototyping the data model. The views, controllers and services are the stock ones generated by "grails generate-all". The image attached shows the index page; clicking on either of the two rightmost columns causes the code to crash; all other columns sort just fine.

Screenshot from 2020-09-14 16-04-44

The crash looks like this:

ArrayIndexOutOfBoundsException occurred when processing request: [GET] /ocupante/index - parameters:
sort: actividades
max: 10
order: asc
0. Stacktrace follows:

java.lang.reflect.InvocationTargetException: null
        at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:211)
        at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:188)
        at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
        at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
        at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
        at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 0
        at org.hibernate.criterion.Order.toSqlString(Order.java:119)
        at org.hibernate.loader.criteria.CriteriaQueryTranslator.getOrderBy(CriteriaQueryTranslator.java:414)
        at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:106)
        at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:75)
        at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:80)
        at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1773)
        at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
        at org.grails.orm.hibernate.query.AbstractHibernateQuery.listForCriteria(AbstractHibernateQuery.java:719)
        at org.grails.orm.hibernate.query.AbstractHibernateQuery.list(AbstractHibernateQuery.java:709)
        at grails.gorm.PagedResultList.<init>(PagedResultList.java:43)
        at grails.gorm.DetachedCriteria$_list_closure2.doCall(DetachedCriteria.groovy:137)
        at grails.gorm.DetachedCriteria$_withPopulatedQuery_closure8.doCall(DetachedCriteria.groovy:769)
        at org.grails.datastore.gorm.GormStaticApi$_withDatastoreSession_closure24.doCall(GormStaticApi.groovy:862)
        at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:319)
        at org.grails.datastore.gorm.AbstractDatastoreApi.execute(AbstractDatastoreApi.groovy:40)
        at org.grails.datastore.gorm.GormStaticApi.withDatastoreSession(GormStaticApi.groovy:861)
        at grails.gorm.DetachedCriteria.withPopulatedQuery(DetachedCriteria.groovy:740)
        at grails.gorm.DetachedCriteria.list(DetachedCriteria.groovy:135)
        at grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
        at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
        at sgs.OcupanteController.index(OcupanteController.groovy:14)
        ... 14 common frames omitted

The code in the controller that provokes this is the "respond" below at line 14:

package sgs

import grails.validation.ValidationException
import static org.springframework.http.HttpStatus.*

class OcupanteController {

    OcupanteService ocupanteService

    static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]

    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond ocupanteService.list(params), model:[ocupanteCount: ocupanteService.count()]
    }


I'm at the very earliest stages in the application, just prototyping the data model. The views, controllers and services are the stock ones generated by "grails generate-all". The image attached shows the index page; clicking on either of the two rightmost columns causes the code to crash; all other columns sort just fine.

Screenshot from 2020-09-14 16-04-44

gradle.properties:
grailsVersion=3.3.9
gormVersion=6.1.11.RELEASE
gradleWrapperVersion=3.5

@sbglasius
Copy link
Member

If you can do a small demo project and push it to github that would be very helpful. Judging from the stacktrace however, this does not look like it happens in the Fields Plugin, but I might be wrong

@monetschemist
Copy link
Author

Sorry I have taken so long to get back to this. I have a workaround that I don't particularly like because I feel it's a bit of a hack; but it both explains the problem and (kind of) solves it.

If you look at the f:table template here:
https://github.com/grails-fields-plugin/grails-fields/blob/master/grails-app/views/templates/_fields/_table.gsp

you will see the following code snippet:

    <thead>
         <tr>
            <g:each in="${domainProperties}" var="p" status="i">
                <g:sortableColumn property="${p.property}" title="${p.label}" />
            </g:each>
        </tr>
    </thead>

The problem is that columns that are one-to-many associations cause the g:sortableColumn tag to crash when the column is selected. I guess that g:sortableColumn should be more robust, but in any case, I don't believe it makes sense to sort on such a column; and if I recall correctly, the old Grails scaffolding (pre fields plugin) did not render such columns as sortable.

My workaround therefore looks at the type of each columnProperty to be rendered to decide whether to render the column as sortable or not. I was originally trying to detect p.type instanceof ManyToOne, following the suggestions at:
https://docs.grails.org/3.3.x/guide/upgrading.html

but after some testing, discovered that according to p.type.toString these columns are interface java.util.Set which I suppose makes sense given the way Gorm creates them.

So my working code replacing the above is:

    <thead>
        <tr>
            <g:each in="${columnProperties}" var="p" status="i">
                <g:if test="${p.type.toString() == 'interface java.util.Set'}">
                    <th>${p.label}</th>
                </g:if>
                <g:else>
                    <g:sortableColumn property="${p.property}" title="${p.label}" />
                </g:else>
            </g:each>
        </tr>
    </thead>

I'm not sure of "the correct solution". We can say that g:sortableColumn should fail more gracefully on this problem, which of course would be nice; or we can accept that it would be a better idea to not suggest that hasMany columns should be sortable in the first place and fix the f:table template.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants