How to avoid the wildcard in the return type

107 views Asked by At

Given the following type hierarchy:

public class GenericBaseClass<T> { }

public class SpecializedClass<T, E extends Enum<E> & SomeInterface> extends GenericBaseClass<T> { }

public class SomeProvider {
    private static final List<SpecializedClass<Foo, ?>> VALUES =
        Arrays.asList(createValue());

    List<SpecializedClass<Foo, ?>> getValues() {        
        return VALUES;
    }

    private static SpecializedClass<Foo, Bar> createValue() {
        return new SpecializedClass<>();
    }
}

public class Foo {}
public enum Bar implements SomeInterface {}
public interface SomeInterface {}

The SomeProvider is supposed to expose a List of available SpecializedClass for the concrete type Foo. (To simplify the example here is only one concretion given for the type Bar.)

According to https://rules.sonarsource.com/java/RSPEC-1452

Generic wildcard types should not be used in return parameters

this snippet is marked as critical code smell by sonar.

Soo far I was not able to get rid of the wildcard here. Changing the getter method to

List<GenericBaseClass<Foo>> getValues() {        
    return VALUES;
}

will avoid the warning, but the client loses the information, that this list only contains instances of SpecializedClass.

Basically I have two questions here:

  1. Is this really such a bad code smell in this case? What might be the pitfalls for the client using this getter method here?

  2. How should the getter look like without using a wildcard in the return type?

Many thanks in advance for your help.

1

There are 1 answers

2
Smutje On

What is wrong using

import java.util.Collections;
import java.util.List;

public class SomeProvider {

  private static final List<SpecializedClass<Foo, Bar>> VALUES =
      Collections.singletonList(createValue());

  List<SpecializedClass<Foo, Bar>> getValues () {
    return VALUES;
  }

  private static SpecializedClass<Foo, Bar> createValue () {
    return new SpecializedClass<>();
  }
}

?

Edit:

Also possible but unsure about your static code analysis is

import java.util.Arrays;
import java.util.List;

public class SomeProvider {

  private static final List<SpecializedClass<Foo, ? extends SomeInterface>> VALUES =
      Arrays.asList(createValue1(), createValue2());

  List<SpecializedClass<Foo, ? extends SomeInterface>> getValues () {
    return VALUES;
  }

  private static SpecializedClass<Foo, Bar1> createValue1 () {
    return new SpecializedClass<>();
  }

  private static SpecializedClass<Foo, Bar2> createValue2 () {
    return new SpecializedClass<>();
  }
}

which at least binds your return type to a subtype of SomeInterface.