Home > database >  Generic wildcards in return types - how to avoid?
Generic wildcards in return types - how to avoid?

Time:08-31

Sonar says

Generic wildcard types should not be used in return types

Now I have to use an API that accepts an Iterable<SomeType<?>> as parameter. How should I create this parameter without violating the Sonar rule if I want to create it in a separate method - so not inline like List<SomeType<?>> param = new ArrayList();

Some code I've played around with:

interface X<T> {

    }
    static class Blarp {
        void addSomeBlarps(Iterable<X<?>> blub) {
        }
    }

    @Test
    void testGenerics() {
        Blarp b = new Blarp();
        X<?> c = new X<>() {};
        X d = new X() {};
        List<X> blarpList = new ArrayList();
        blarpList.add(c);
        blarpList.add(d);
        List<X<?>> blubList = new ArrayList<>();
        blubList.add(c);
        blubList.add(d);
//        blubList.addAll(blarpList); does not work - why? why can a single X be added but not multiple?
//        blubList.addAll((Collection<? extends X<?>>) blarpList); does seem to work with IntelliJ but then fails on compile

//        b.addSomeBlarps(blarpList); doesn't work - why?
        b.addSomeBlarps(blubList);
    }

CodePudding user response:

Probably there's a misunderstanding.

Let's have a look at

public void someMethod(SomeType<?> param) { ... }

This method accepts a parameter param which has to be of the parameterized type SomeType but the method doesn't mind the type parameter (put casually). That is, you can call this method with any parameter of type SomeType regardless of the used type parameter.

So, you can create your objects with a concrete type parameter and hand it over to the method, for example

public class Test<T> {
    public static void main(String[] args) {
        print(newTestString());
        print(newTestLong());
    }

    public static void print(Test<?> someTest) {
        System.out.println(someTest);
    }

    public static Test<String> newTestString() {
        return new Test<String>();
    }

    public static Test<Long> newTestLong() {
        return new Test<Long>();
    }
}

Update

The misunderstanding was at my side as it's about a generic type of a generic type. That's a different story. In the example the type is an Iterable which is parameterized by SomeType<?>. The problem is, that Iterable<SomeType<String>> is not a subtype of Iterable<SomeType<?>>.

The method would have to accept e. g. a parameter of type Iterable<? extends SomeType<?>> to be able to pass a Iterable<SomeType<String>>.

As the method is given the way it is, you'll have to work around.

(EDIT: deleted crap I wrote)

I would either not factor out the creation of the object or suppress the warning in that case.

  • Related