[JIRA] Created: (GLAZEDLISTS-567) Old/new values retrieved from SimpleFunctionList events are of the wrong type

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[JIRA] Created: (GLAZEDLISTS-567) Old/new values retrieved from SimpleFunctionList events are of the wrong type

JIRA jira-no-reply@java.net
Old/new values retrieved from SimpleFunctionList events are of the wrong type
-----------------------------------------------------------------------------

                 Key: GLAZEDLISTS-567
                 URL: https://java.net/jira/browse/GLAZEDLISTS-567
             Project: glazedlists
          Issue Type: Bug
          Components: core
    Affects Versions: 1.9.0
         Environment: Not platform dependent
            Reporter: mcormier


When using a {{SimpleFunctionList}} (typically via {{GlazedLists.transformByFunction()}}), having a list event listener that accesses {{Event.getOldValue()}} will lead to unexpected {{ClassCastException}}s.  Below is a failing test case, along with one that works once {{SimpleFunctionList}} is modified to apply the transformation function on the elements stored in the event.  (The demonstrated fix is a bit convoluted because most of the functionality required to fix the issue is private or protected).  Possible workarounds are to use a {{FunctionList}} instead, to rewrite your code to avoid calling {{getOldValue()}} (which is deprecated, but very useful), or to write your own implementation (which removes the main selling point for GL).

{code:title=TestTransformByFunction.java|borderStyle=solid}
package glazedliststests;

import junit.framework.TestCase;

import ca.odell.glazedlists.*;
import ca.odell.glazedlists.FunctionList.Function;
import ca.odell.glazedlists.event.*;


public class TestTransformByFunction extends TestCase {

   private Integer oldValue;
   private ListEventListener<Integer> listener = new ListEventListener<Integer>() {
      @SuppressWarnings("deprecation")
      @Override
      public void listChanged(ListEvent<Integer> event) {
         event.next();
         oldValue = event.getOldValue();
      }
   };
   private Function<String,Integer> function = new Function<String,Integer>() {
      @Override
      public Integer evaluate(String s) {
         return Integer.parseInt(s);
      }
   };

   public void testTransformRemovalListening() {
      EventList<String> strings = GlazedLists.eventListOf("1", "2", "3");
      EventList<Integer> ints = GlazedLists.transformByFunction(strings, function);
      ints.addListEventListener(listener);
      strings.remove(1);
      assertEquals(Integer.valueOf(2), oldValue);
   }

   public void testTransformRemovalListeningFix() {
      EventList<String> strings = GlazedLists.eventListOf("1", "2", "3");
      EventList<Integer> ints = new FixedSimpleFunctionList<>(strings, function);
      ints.addListEventListener(listener);
      strings.remove(1);
      assertEquals(Integer.valueOf(2), oldValue);
   }
}



/**
 * A patched SimpleFunctionList that intercepts events from the original
 * list and applies the transformation function on the event's old and new
 * values.
 */
final class FixedSimpleFunctionList<S, E> extends TransformedList<S, E> {

    private final Function<S,E> function;

    public FixedSimpleFunctionList(EventList<S> source, Function<S, E> function) {
        super(source);
        this.function = function;
        source.addListEventListener(this);
    }

    @Override
    public E get(int index) {
        final S elem = source.get(index);
        return function.evaluate(elem);
    }

    @Override
    public void listChanged(ListEvent<S> listChanges) {
        forwardEvent(listChanges);
    }

    /**
     * This was copied from {@link ListEventAssembler#forwardEvent(ListEvent)},
     * but modified to invoke the transform function on the old and new values.
     */
    private void forwardEvent(ListEvent<?> listChanges) {
        updates.beginEvent(false);
//        updates.reorderMap = null;    XXX Not accessible, but not required in this simple test
        if (updates.isEventEmpty() && listChanges.isReordering()) {
           updates.reorder(listChanges.getReorderMap());
        } else {
            while (listChanges.next()) {
                int type = listChanges.getType();
                int index = listChanges.getIndex();
                switch (type) {
                   case ListEvent.DELETE:
                      updates.elementDeleted(index,
                            (E) function.evaluate((S) listChanges.getOldValue()));
                      break;
                   case ListEvent.UPDATE:
                      updates.elementUpdated(index,
                            (E) function.evaluate((S) listChanges.getOldValue()),
                            (E) function.evaluate((S) listChanges.getNewValue()));
                      break;
                   case ListEvent.INSERT:
                      updates.elementInserted(index,
                            (E) function.evaluate((S) listChanges.getNewValue()));
                      break;
                }
            }
            listChanges.reset();
        }
        updates.commitEvent();
    }

    @Override
    protected boolean isWritable() {
        return false;
    }
}
{code}

--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: https://java.net/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira