Java generics "capture of ?"

42,462

Solution 1

A wildcard represents an unknown type.

wildcard capture is the process of binding the value of a wildcard type to a new type variable. For example:

List<?> list = ...;
shuffle(list);

where

<T> void shuffle(List<T> list) {
    ...
}

Here, the unknown value of ? is bound to the new type variable T upon invocation of the shuffle method, allowing the shuffle method to refer to that type.

The Java compiler internally represents the value of a wildcard by capturing it in an anonymous type variable, which it calls "capture of ?" (actually, javac calls them "capture #1 of ?" because different uses of ? may refer to different types, and therefore have different captures).

Ok, so what is wrong in your code? You are trying to invoke a method

<S,T> setCellFactory(Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> factory);

with

Callback<TreeTableColumn<S,?>, TreeTableCell<S, ?>> factory;

In the method signature, the type parameter T stands for a single type, that must be provided by the caller. As a convenience, the compiler automatically attempts to infer a suitable value (-> type inference). Your compilation error means that the compiler was unable to do so.

In this instance, this is not a shortcoming of type inference, as it is actually impossible to assign a suitable value to T, because both ? need to be subtypes of T, but the compiler can not know that the two ? stand for the same type, or even related types.

To successfully invoke this method, your argument type must use the same type for all occurrences of T. If you already have such a type at hand, go ahead and use it. Otherwise, you may be able to introduce one using wildcard capture:

setCellFactory(newFactory());

where

<S,T> Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> newFactory() {
    return new Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> {
        ...
    }
}

Solution 2

from what I found from what is a capture conversion and oracle capture generic docs it looks like you are facing some problem where the compiler can't find the needed helper class, or tries to place Object in there, but what you give him can not be converted safely.

EDIT:

DEFAULT_CELL_FACTORY

public static final Callback<TreeTableColumn<?,?>,TreeTableCell<?,?>>

If no cellFactory is specified on a TreeTableColumn instance, then this one will be used by default. At present it simply renders the TableCell item property within the graphic property if the item is a Node, or it simply calls toString() if it is not null, setting the resulting string inside the text property.

and

setCellFactory

public final void setCellFactory(Callback<TreeTableColumn<S,T>,TreeTableCell<S,T>> value)

Sets the value of the property cellFactory. Property description: The cell factory for all cells in this column. The cell factory is responsible for rendering the data contained within each TreeTableCell for a single TreeTableColumn. By default TreeTableColumn uses a default cell factory, but this can be replaced with a custom implementation, for example to show data in a different way or to support editing. There is a lot of documentation on creating custom cell factories elsewhere (see Cell and TreeTableView for example).

Finally, there are a number of pre-built cell factories available in the javafx.scene.control.cell package.

taken out from Java 8 API Doc.

so something like this should be going more into the right direction:

public static <S> Callback<TableColumn<S,String>, TableCell<S,String>> forTableColumn() {
   return forTableColumn(new DefaultStringConverter());
}

or something like this depending on what excactly you want to give into the Cell.

setCellFactory(TextFieldTableCell.<DataModel, Integer>forTableColumn(new IntegerStringConverter()));

these code snippets are taken from This StackOverflow Thread

and last this link could help you too: TableView Cell Tutorial

So this should give you some more light in the dark about what might be causing the problem.

Share:
42,462
kotycheese
Author by

kotycheese

Updated on July 22, 2022

Comments

  • kotycheese
    kotycheese almost 2 years

    I'm working with a TreeTable and when changing cell factory I am required to pass a

    Callback<TreeTableColumn<A, capture of ?>, TreeTableCell<A, capture of ?>>
    

    where A is a class I am working with but I have no idea how to work with the "capture of ?"

    I tried to create

    new Callback<TreeTableColumn<A, ?>, TreeTableCell<A, ?>>
    

    but IDEA shows warning

    setCellFactory(Callback<TreeTableColumn<A, capture<?>>, TreeTableCell<A, capture<?>>>) in TreeTableColumn cannot be applied to (anonymous Callback<TreeTableColumn<A, ?>, TreeTableCell<A, ?>>)
    

    I tried using specific classes (like String) instead of "?" as well, but nothing helped.

    Could anyone explain to me how to work with this?

    Thank you.

    EDIT:

    I gathered a little bit more information.. the CellFactory of TreeTableColumn<S,T> should be Callback<TreeTableColumn<S,T>,TreeTableCell<S,T>>, however, the TreeTableColumn that I'm working with is created as a raw type (in a library).

    Using a raw type Callback works. But are there any other options how to work this around?