Skip to Content
0
Former Member
Feb 05, 2019 at 12:05 PM

Unsupported operation when handling refresh of objects in Backoffice

129 Views

Hello,

I have been digging in to our logs and found one error in Backoffice that keeps happening. We are running Hybris 6.7

When some CRUD operation is performed in Backoffice the backing objectFacade send out events to notify other widgets that an object changed so that they can update their models if needed. One such event goes through: com.hybris.cockpitng.widgets.collectionbrowser.mold.impl.DefaultSelectAndFocusDelegateController#handleSelectionRefresh

This looks like this:

 protected void handleSelectionRefresh(Collection<?> updatedObjects) {
         List<Object> oldObjects = new LinkedList();
         Collection<Object> selectedItems = this.getController().getSelectedItems();
         updatedObjects.forEach((updatedObject) -> {
             selectedItems.stream().filter((oldObject) -> {
                 return oldObject.equals(updatedObject);
             }).forEach(oldObjects::add);
         });
         if (!oldObjects.isEmpty()) {
             selectedItems.removeAll(oldObjects);
             selectedItems.addAll(updatedObjects);
             this.getController().getModel().changed("selectedObjects");
         }
 
         this.getController().handleSelectionRefresh(updatedObjects);
     }

Notice the if case when oldObjects isn't empty. Then it removes all objects in the selectedItems collection and adds the latest updated objects. Now lets see where these selectedItems come from:

 public <E> Collection<E> getSelectedItems() {
         WidgetModel widgetModel = this.getController().getWidgetInstanceManager().getModel();
         Optional<Collection> selected = Optional.ofNullable(widgetModel.getValue("selectedObjects", Collection.class));
         Collection<E> result = (Collection)selected.orElse(Collections.emptyList());
         if (!this.getController().isMultiSelectEnabled() && CollectionUtils.size(result) > 1) {
             result = Collections.singleton(SelectAndFocusDelegateController.getSelectedItem((Collection)result));
         }
 
         return (Collection)result;
     }

Now look at that if case there. Notice what it sets the result to an immutable singleton set in case it goes there. So when this happens and there are old objects it will try to do removeAll on that returned immutable singleton set which is an unsupported operation.

This must be a bug right? In any case if other people find this in their logs you can extend: com.hybris.cockpitng.widgets.collectionbrowser.mold.impl.DefaultSelectAndFocusDelegateController

 @Override
     public <E> Collection<E> getSelectedItems() {
         return new LinkedHashSet<>(super.getSelectedItems());
     }

Now it will not crash here and everything will work. So what is the result that it crashes here? Well, not super obvious because this affects the related widgets during the last step of refreshing their models so it won't be the first thing you notice but it really shouldn't crash here regardless.

Regards