glazedlists
  1. glazedlists
  2. GLAZEDLISTS-510

Add ability to handle covariant element types in GlazedLists.readOnlyList a'la Collections.unmodifiableXXXX

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.8.0
    • Fix Version/s: 1.9.0
    • Component/s: core
    • Labels:
      None

      Description

      The jdk Collections.unmodifiableXXX methods allow conversion of a list of elements to a list of elements of a covariant type; ie. List<? extends T> to a List<T>. Currently GlazedLists.readOnlyList doesn't allow this kind of conversion.

      The only API change required would be to either:
      1) alter the existing readOnlyList method to return an EventList<E> rather than a TransformedList<E, E> (I'd suggest that an EventList should be returned in any case)
      2) or (to maintain backwards compatibility) add an extra method:
      static <E> EventList<E> unmodifiableList(EventList<? extends E> source);

        Activity

        Hide
        jason_s added a comment -

        any comments from the project maintainers?

        Show
        jason_s added a comment - any comments from the project maintainers?
        Hide
        jason_s added a comment - - edited

        FWIW I've changed my opinion of the priority: I think it should be major.

        The reason is that if you have a class that stores an EventList<X> where X is a private subclass of some well-known type Foo, and you want to export an EventList<Foo>, you're stuck. (by "export" I mean return that list via a getter method.) You can only export an EventList<? extends Foo>, and at that point it is either cumbersome or impossible to instantiate TableFormat s or TableModel s that act on the resulting list.

        Show
        jason_s added a comment - - edited FWIW I've changed my opinion of the priority: I think it should be major. The reason is that if you have a class that stores an EventList<X> where X is a private subclass of some well-known type Foo , and you want to export an EventList<Foo> , you're stuck. (by "export" I mean return that list via a getter method.) You can only export an EventList<? extends Foo> , and at that point it is either cumbersome or impossible to instantiate TableFormat s or TableModel s that act on the resulting list.
        Hide
        timpatt added a comment -

        I think your argument for changing the task's priority is sound. The actual change is quite simple - I've just implemented the one line in my own utility class. Would nice to have it actually integrated into the library, though!

        Show
        timpatt added a comment - I think your argument for changing the task's priority is sound. The actual change is quite simple - I've just implemented the one line in my own utility class. Would nice to have it actually integrated into the library, though!
        Hide
        brands added a comment -

        will be addressed for the next release...

        Show
        brands added a comment - will be addressed for the next release...
        Hide
        brands added a comment - - edited

        So, would the following be ok for you in GlazedLists class?

            public static <E> TransformedList<E, E> readOnlyList(EventList<? extends E> source) {
                return new ReadOnlyList<E>((EventList<E>) source);
            }
        

        Given classes
        "Concrete extends Derived extends AbstractBase" you could do the following:

            public void testGenericsFactoryMethod() {
            	final EventList<AbstractBase> baseList = new BasicEventList<AbstractBase>();
            	final EventList<Derived> derivedList = new BasicEventList<Derived>();
            	final EventList<Concrete> concreteList = new BasicEventList<Concrete>();
        
            	final EventList<AbstractBase> readOnlyBaseList = GlazedLists.readOnlyList(baseList);
            	final TransformedList<AbstractBase, AbstractBase> treadOnlyBaseList = GlazedLists.readOnlyList(baseList);
            	final EventList<Derived> readOnlyDerivedList = GlazedLists.readOnlyList(derivedList);
            	final TransformedList<Derived, Derived> treadOnlyDerivedList = GlazedLists.readOnlyList(derivedList);
            	final EventList<Concrete> readOnlyConcreteList = GlazedLists.readOnlyList(concreteList);
            	final TransformedList<Concrete, Concrete> treadOnlyConcreteList = GlazedLists.readOnlyList(concreteList);
        
            	// wasn't possible before:
            	final EventList<AbstractBase> readOnlyBaseDerivedList = GlazedLists.<AbstractBase>readOnlyList(derivedList);
            	final TransformedList<AbstractBase, AbstractBase> treadOnlyBaseDerivedList = GlazedLists.<AbstractBase>readOnlyList(derivedList);
            	final EventList<AbstractBase> readOnlyBaseConcreteList = GlazedLists.<AbstractBase>readOnlyList(concreteList);
            	final TransformedList<AbstractBase, AbstractBase> treadOnlyBaseConcreteList = GlazedLists.<AbstractBase>readOnlyList(concreteList);
            	final EventList<Derived> readOnlyDerivedConcreteList = GlazedLists.<Derived>readOnlyList(concreteList);
            	final TransformedList<Derived, Derived> treadOnlyDerivedConcreteList = GlazedLists.<Derived>readOnlyList(concreteList);
            }
        

        A TransformedList is returned to indicate that it is a transformation, e.g. the returned list has to be disposed if not used anymore.
        But you can treat TransformedList<E, E> as EventList<E> if you like, as shown above.

        Show
        brands added a comment - - edited So, would the following be ok for you in GlazedLists class? public static <E> TransformedList<E, E> readOnlyList(EventList<? extends E> source) { return new ReadOnlyList<E>((EventList<E>) source); } Given classes "Concrete extends Derived extends AbstractBase" you could do the following: public void testGenericsFactoryMethod() { final EventList<AbstractBase> baseList = new BasicEventList<AbstractBase>(); final EventList<Derived> derivedList = new BasicEventList<Derived>(); final EventList<Concrete> concreteList = new BasicEventList<Concrete>(); final EventList<AbstractBase> readOnlyBaseList = GlazedLists.readOnlyList(baseList); final TransformedList<AbstractBase, AbstractBase> treadOnlyBaseList = GlazedLists.readOnlyList(baseList); final EventList<Derived> readOnlyDerivedList = GlazedLists.readOnlyList(derivedList); final TransformedList<Derived, Derived> treadOnlyDerivedList = GlazedLists.readOnlyList(derivedList); final EventList<Concrete> readOnlyConcreteList = GlazedLists.readOnlyList(concreteList); final TransformedList<Concrete, Concrete> treadOnlyConcreteList = GlazedLists.readOnlyList(concreteList); // wasn't possible before: final EventList<AbstractBase> readOnlyBaseDerivedList = GlazedLists.<AbstractBase>readOnlyList(derivedList); final TransformedList<AbstractBase, AbstractBase> treadOnlyBaseDerivedList = GlazedLists.<AbstractBase>readOnlyList(derivedList); final EventList<AbstractBase> readOnlyBaseConcreteList = GlazedLists.<AbstractBase>readOnlyList(concreteList); final TransformedList<AbstractBase, AbstractBase> treadOnlyBaseConcreteList = GlazedLists.<AbstractBase>readOnlyList(concreteList); final EventList<Derived> readOnlyDerivedConcreteList = GlazedLists.<Derived>readOnlyList(concreteList); final TransformedList<Derived, Derived> treadOnlyDerivedConcreteList = GlazedLists.<Derived>readOnlyList(concreteList); } A TransformedList is returned to indicate that it is a transformation, e.g. the returned list has to be disposed if not used anymore. But you can treat TransformedList<E, E> as EventList<E> if you like, as shown above.
        Hide
        brands added a comment -

        Fixed as commented above with revision 2342.
        Also changed
        threadSafeList(EventList<E> source)
        to
        threadSafeList(EventList<? extends E> source)

        Show
        brands added a comment - Fixed as commented above with revision 2342. Also changed threadSafeList(EventList<E> source) to threadSafeList(EventList<? extends E> source)

          People

          • Assignee:
            brands
            Reporter:
            timpatt
          • Votes:
            1 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: