A tricky interaction between SettingsFacet and Query Parameters in Jmix 2.x

Hi everybody!

I just want to share a new discovery I made while working with Jmix 2.x.

The scenario is the following:

  • a List View with facets enabled: Settings + Query Parameters
  • a custom filter is created and marked as default using “Make default”
    (this is possible thanks to the Settings facet enabled alongside the Query Parameters one)

So far, so good.

Now comes the tricky part :brain:

Imagine this flow:

  • you create another filter (not the default one)
  • you apply it
  • you double-click on a row in the results

As expected, you are navigated to the Detail View of the entity. Nothing strange here.

:point_right: Now imagine going back using the browser history or simply refreshing the url page with Command+R (or F5)

What should happen is that the browser restores the previous List View URL.
Since the Query Parameters facet is enabled, the URL contains something like:

&genericFilterConfiguration=CustomFilterxNFhkwiF

Here’s where things get… interesting :smile:

What actually happens is:

  • the List View enters beforeEnter
  • the query parameters change event is fired
  • the filter configuration from the query params is applied
  • this triggers another query change event
  • the SettingsFacetImpl listener is triggered
  • applyDataLoadingSettings() is executed
  • user settings are loaded for the genericFilter
  • since a filter was marked as default in the settings…
  • :point_right: the current filter configuration is reset to the default one, completely ignoring the value coming from genericFilterConfiguration in the URL
  • the List View finally loads data based on the default filter, not the one from the query params

This is probably a 1-in-10,000 scenario
Of course, I managed to hit exactly that one :sweat_smile:

IMHO, the correct behavior should be:

  • SettingsFacetImpl should check whether genericFilterConfiguration is present in the query parameters
  • if it is present → load that configuration
  • otherwise → fall back to the default configuration from the settings

I’ve been working with Jmix for quite a few years now, and I’m really happy both to use it and to debug it :stuck_out_tongue:
So it was fairly straightforward to find the right place to introduce this enhancement.

There is a class called SettingsFacetUrlQueryParametersHelper which is responsible for removing components from the list of settings-aware components for a view.

The cleanest way I found to handle this corner case was to extend this Spring bean and bypass the settings application when a genericFilterConfiguration parameter is present in the URL.

Here’s my custom helper:

@Primary
@Component("custom_SettingsFacetUrlQueryParametersHelper")
public class CustomSettingsFacetUrlQueryParametersHelper
        extends SettingsFacetUrlQueryParametersHelper {

    @Override
    public boolean containsParametersForBinder(QueryParameters queryParameters,
                                               UrlQueryParametersFacet.Binder binder) {
        if (binder instanceof PaginationUrlQueryParametersBinder paginationBinder) {
            return containsParametersForPagination(queryParameters.getParameters(), paginationBinder);
        }

        // custom logic
        if (binder instanceof GenericFilterUrlQueryParametersBinder) {
            return queryParameters.getParameters()
                    .containsKey("genericFilterConfiguration");
        }

        return super.containsParametersForBinder(queryParameters, binder);
    }
}

I just wanted to share this in case it helps someone else —
and also to ask the Jmix dev team whether this behavior could be integrated by default into the Settings helper.

Thanks everybody!
Ale