6

I'm struggling to capture a wildcard when it is "nested in another wildcard". Is it possible?

The code:

public class ConvolutedGenerics {

    // listClass is a class implementing a List of some Serializable type
    public void doSomethingWithListOfSerializables(
            Class<? extends List<? extends Serializable>> listClass) {

        // Capture '? extends Serializable' as 'T extends Serializable'
        // The line does not compile with javac 7
        captureTheWildcard(listClass); // <------ zonk here
    }

    // listClass is a class implementing a List of some Serializable type
    private <T extends Serializable>
            void captureTheWildcard(
                    Class<? extends List</* ? extends */T>> listClass) {

        // Do something
    }
}

compiled with javac 7 produces:

ConvolutedGenerics.java:18: error: method captureTheWildcard in class ConvolutedGenerics cannot be applied to given types;
                captureTheWildcard(listClass);
                ^
  required: Class<? extends List<T>>
  found: Class<CAP#1>
  reason: no instance(s) of type variable(s) T exist so that argument type Class<CAP#1> conforms to formal parameter type Class<? extends List<T>>
  where T is a type-variable:
    T extends Serializable declared in method <T>captureTheWildcard(Class<? extends List<T>>)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends List<? extends Serializable> from capture of ? extends List<? extends Serializable>
1 error

Besides many more simpler cases I've found

but I could not infer an answer for my problem from those.

Community
  • 1
  • 1
Piotr Findeisen
  • 19,480
  • 2
  • 52
  • 82
  • Why this form is not going to work for you: private void captureTheWildcard( Class extends List extends T>> listClass)? – Archer Sep 20 '13 at 08:39
  • @archer, why? If I did, then I think `T` would be always inferred as `Serializable`, so it would not actually capture the wildcard, would it? And then I may have problem inside `captureTheWildcard`. – Piotr Findeisen Sep 20 '13 at 21:17

2 Answers2

4

It is not possible, as you probably already know.

Let me illustrate with a counter-example:

List<Integer> foo = Arrays.asList(1,2,3);
List<String> bar = Arrays.asList("hi","mom");
List<List<? extends Serializable>> baz = Arrays.asList(foo, bar);
doSomethingWithListOfSerializables(baz);

public void doSomethingWithListOfSerializables(
        List<? extends List<? extends Serializable>> listList) {

    captureTheWildcard(listList); 
}

private <T extends Serializable>
        void captureTheWildcard(
                List<? extends List<T>> listList) {

    // Do something
}

What should T be?

newacct
  • 119,665
  • 29
  • 163
  • 224
  • In your example there is no wildcard in a "top" generic. This makes a big difference IMHO. In my problem the "nested" wildcard is a function (could be derived from) the top wildcard, if that was known. – Piotr Findeisen Sep 22 '13 at 16:39
  • @PiotrFindeisen: NO. The parameter of `doSomethingWithListOfSerializables()`, `listList`, has a top wildcard, does it not? It's that that gets passed to that `captureTheWildcard()` method. – newacct Sep 23 '13 at 02:38
  • yes, but `baz` does not. Your code is "of course incorrect", `baz` is of a *concrete* type `List>` (*concrete!*), and mine `listClass` was *not of a concrete type*. – Piotr Findeisen Sep 23 '13 at 08:12
  • @PiotrFindeisen: You are wrong. `baz` doesn't matter. Once it gets passed to `doSomethingWithListOfSerializables()`, inside that function, you only have a `List extends List extends Serializable>>`. "Capture" only happens when you pass to a generic method, i.e. when you pass to `captureTheWildcard()`. That generic is passed `listList` from `doSomethingWithListOfSerializables()`, which is a `List extends List extends Serializable>>`. – newacct Sep 23 '13 at 09:17
0

The problem with your code is that you're trying to call captureTheWildcard passing different typed parameter then defined here:

private <T extends Serializable> void captureTheWildcard(Class<? extends List<T>> listClass)

You should explicitly say in your method definition that parameter passed is actually of type of Class<? extends List<? extends Serializable>>or modify the type of listClass like this:

import java.util.List;
import java.io.Serializable;

public class ConvolutedGenerics {

    // listClass is a class implementing a List of some Serializable type                                                                           
    public <T extends Serializable> void doSomethingWithListOfSerializables(
                                                   Class<? extends List<T>> listClass) {

        // Capture '? extends Serializable' as 'T extends Serializable'                                                                             
        // The line does not compile with javac 7                                                                                                   
        captureTheWildcard(listClass); // <------ zonk here                                                                                         
    }

    // listClass is a class implementing a List of some Serializable type                                                                           
    private <T extends Serializable> void captureTheWildcard(Class<? extends List<T>> listClass) {

        // Do something                                                                                                                             
    }
}

Compiles well with javac 1.7.0_25

Archer
  • 5,073
  • 8
  • 50
  • 96
  • Well, I didn't say that, but I knew it well that using the same `T extends Serializable` on `doSomethingWithListOfSerializables` makes the code compile. But then -- there is no "how to capture" problem and no question. Hopefully, your answer may help others, but does not help me. – Piotr Findeisen Sep 20 '13 at 21:13
  • to capture what? Just explain what you're trying to achieve. – Archer Sep 20 '13 at 21:17
  • To capture `T`. The whole point of the question is that I don't want to have `T` on `doSomethingWithListOfSerializables`. Or, more precisely, I can have a variable, collection element or something instead of a method call to `doSomethingWithListOfSerializables` -- so nothing I could add `T` to, actually. – Piotr Findeisen Sep 20 '13 at 21:18