2
public class GetResponse <T extends KeywordIdentifier>{

    private List<KeywordMetrics<T>> metrics = null;


public List<KeywordMetrics<T>> getMetrics(){
        return this.metrics;
    }

    public void setMetrics(List<KeywordMetrics<T>> metrics){
        this.metrics = metrics;
    }
}


public class AdWordsKeywordIdentifier extends KeywordIdentifier {
//body
}
public class BingKeywordIdentifierextends KeywordIdentifier {
//body
}


GetResponse<? extends KeywordIdentifier> result= new GetResponse<AdWordsKeywordIdentifier>();
List<KeywordMetrics<AdWordsKeywordIdentifier>> stats = getGoogleStats();
List<KeywordMetrics<BingKeywordIdentifier>> stats2 = getBingStats();
result.setMetrics(stats);
result.setMetrics(stats2);

result.setMetrics(stats) method produces compile error.

ERROR (The method setMetrics(List<KeywordMetrics<capture#2-of ?extends KeywordIdentifier>>) in the type GetResponse<capture#2-of ?extends KeywordIdentifier> is not applicable for the arguments(List<KeywordMetrics<AdWordsKeywordIdentifier>>)

Could you please explain me why is that and how I can fix it?

2 Answers 2

6

You need to declare result as what it is, i.e., a GetResponse<AdWordsKeywordIdentifier>.

EDIT:

Looking at your change I see one big problem. You are trying to call the setMetrics method with two lists of two different types. You simply cannot do that. Since GetResponse is parameterized with T, the type of the elements in the list must be exactly T, that is, either AdWordsKeywordIdentifier or BingKeywordIdentifier, it can't be both. The compiler is complaining because GetResponse has type parameter ? extends KeywordIdentifier and it cannot possibly infer what the actual type parameter is, so it can't statically ensure type safety for the method calls to setMetrics, i.e., you will never be able to call it.

Not all is lost though. You have to make a choice: either leave your generic class as is and enforce strong typing at all times or you can make the class not generic and modify the metrics field as follows:

class GetResponse {

  private List<? extends KeywordMetrics<? extends KeywordIdentifier>> metrics = null;

  public List<? extends KeywordMetrics<? extends KeywordIdentifier>> getMetrics() {
    return this.metrics;
  }

  public void setMetrics(List<? extends KeywordMetrics<? extends KeywordIdentifier>> metrics) {
    this.metrics = metrics;
  }
}

which will now only work for your original snippet:

GetResponse result = new GetResponse();
List<KeywordMetrics<AdWordsKeywordIdentifier>> stats = new ArrayList<>();
List<KeywordMetrics<BingKeywordIdentifier>> stats2 = new ArrayList<>();    result.setMetrics(stats);
result.setMetrics(stats2);

It all depends on what you are trying to achieve. The code above is still type safe. Since you said you want your code "generic" you have to give up knowing the exact type of your list at compile time (it is now a list of ? extends KeywordMetrics<? extends KeywordIdentifier>).

Note that the double wildcard is required to make this compile. A List<KeywordMetrics<BingKeywordIdentifier>> is a List<? extends KeywordMetrics<? extends KeywordIdentifier>> but it is not a List<KeywordMetrics<? extends KeywordIdentifier>>.

Sign up to request clarification or add additional context in comments.

4 Comments

Yes, but I don't want to loose generic principle. My point is that I want create Generic result, so that I can feed any parameter in it. I've updated my post, could you please take a look?
@WildGoat See my updated answer, you are at a stalemate I believe.
@WildGoat No problem. What did you end up using?
I stick with T but rethink and restructured my project a bit. :)
5

You didn't declare variable result with the correct type parameterization. Therefore, the compiler can't guarantee that calling the setMetrics method with this list should work.

Changing it to

GetResponse<AdWordsKeywordIdentifier> result = ....

should fix it.

2 Comments

Yes, but I don't want to loose generic principle. My point is that I want create Generic result, so that I can feed any parameter in it. I've updated my post, could you please take a look?
I'm not quite sure what you want to achieve then. Assigning the GetResponse<AdWordsKeywordIdentifier> and then expecting setMetrics to work with BingStats doesn't really make sense to me. It seems to me that you might be over-complicating things here by using generics. An important point to note is that even if B is a subclass of A, that doesn't make List<B> a subclass of List<A>, and that might pose a problem for your current code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.