Skip to content

ListItemWriter<T>::getWrittenItems has bad wildcard return type #4576

Closed
@commonquail

Description

@commonquail

Spring Batch 5.1.1's ListItemWriter<T>::getWrittenItems has the bounded wildcard generic return type List<? extends T>. It is evident from the field's type, List<T>, that the method return type's bounded wildcard contributes nothing of value, but besides this some constructs end up inferring the specific element type ? extends T where only a T can work, necessitating otherwise redundant explicit type parameter specification. This ergonomics breakage manifests trivially in AssertJ's ListAssert<ELEMENT>, which happens to feature an API that appears counter-productively genericized, but it is easy to show with plain JDK APIs that the correct return type should be List<T>; consider:

import java.util.*;

class T {
    void foo() {
        var writer = new LiWr<Element>();

        var without = writer.itemsWithoutWildcard();   // List<Element>
        var mutableWithout = new ArrayList<>(without); // ArrayList<Element>
        mutableWithout.add(new Element());

        // T.java:18: error: incompatible types: Element cannot be converted to CAP#1
        //         mutableWith.add(new Element());
        //                         ^
        //   where CAP#1 is a fresh type-variable:
        //     CAP#1 extends Element from capture of ? extends Element
        var with = writer.itemsWithWildcard();   // List<? extends Element>
        var mutableWith = new ArrayList<>(with); // ArrayList<? extends Element>
        mutableWith.add(new Element());

        // T.java:25: error: incompatible types: List<CAP#1> cannot be converted to List<Element>
        //         List<Element> with2 = writer.itemsWithWildcard();   // List<? extends Element>
        //                                                       ^
        //   where CAP#1 is a fresh type-variable:
        //     CAP#1 extends Element from capture of ? extends Element
        List<Element> with2 = writer.itemsWithWildcard();   // List<? extends Element>

        // ok
        var with3 = writer.itemsWithWildcard();
        List<Element> mutableWith2 = new ArrayList<>(with);
    }
}

class LiWr<T> {
    final List<T> writtenItems = new ArrayList<>();
    List<? extends T> itemsWithWildcard()    { return this.writtenItems; }
    List<T>           itemsWithoutWildcard() { return this.writtenItems; }
}

class Element {}

Effective Java 3rd Ed. item 32 also says

Do not use bounded wildcard tyeps as return types.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions