The class used (in Java, third party API, not changeable):
public class BookmarkablePageLink<T> extends Link<T> {
public <C extends Page> BookmarkablePageLink(final String id, final Class<C> pageClass)
And now I want to call this from Kotlin:
item.queue(BookmarkablePageLink("link", bookmark.page))
bookmark.page
is in Java, and it is: public Class<? extends WebPage> getPage()
None of these work:
item.queue(BookmarkablePageLink("link", bookmark.page))
Error: Not enough information to infer parameter T in
constructor Bookmarkable PageLink<T : Any!, C : Page!>(...)
item.queue(BookmarkablePageLink<>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, *>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, in WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, out WebPage>("link", bookmark.page))
item.queue(BookmarkablePageLink<Any, T : WebPage>("link", bookmark.page))
This would be the "hypothetically correct" way to do this in Javaish-speak (just the intention, but it's not real code), but this isn't supported by Kotlin:
item.queue(BookmarkablePageLink<Any, ? extends WebPage>("link", bookmark.page))
My best workaround is this, which is ugly, but works:
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>))
Surprisingly in Java this was simply:
item.queue(new BookmarkablePageLink<>("link", bookmark.getPage() ));
Use an upper-bounded wild card only when values are to be retrieved and processed and the data structure (ArrayList) won't be changed. This means that the corresponding argument of a call on m2 can be an ArrayList whose elements are of any class that is Integer or a superclass of Integer, including Number and Object.
The unbounded wildcard type is specified using the wildcard character (?), for example, List<?>. This is called a list of unknown type. There are two scenarios where an unbounded wildcard is a useful approach: If you are writing a method that can be implemented using functionality provided in the Object class.
Variable number of arguments (varargs) Only one parameter can be marked as vararg . If a vararg parameter is not the last one in the list, values for the subsequent parameters can be passed using named argument syntax, or, if the parameter has a function type, by passing a lambda outside the parentheses.
What is the difference between a wildcard bound and a type parameter bound? A wildcard can have only one bound, while a type parameter can have several bounds. A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter.
So far as I understand, BookmarkablePageLink(...)
should be approximately equivalent to new BookmarkablePageLink<>
in Java, so this is the option which "should" work. All others you tried shouldn't, each for different reasons.
Constructors which have their own type parameters are very rare (before seeing this question I thought they were illegal), so they may be overlooked somewhere in Kotlin compiler. A possible workaround is to make it a function instead:
fun <T, C : Page> makeBookmarkablePageLink(id: String, clazz: Class<C>): BookmarkablePageLink<T> =
BookmarkablePageLink<T, C>(id, clazz)
and then
item.queue(makeBookmarkablePageLink("link", bookmark.page))
I'll also note that I'm pretty sure
the "correct" way to do this in Java-speak
is actually wrong; and in fact you can't write down the type parameters in Java explicitly, because the second type parameter is a captured wildcard.
I am creating a answer from all the best comments because those already seem very valuable.
Workaround from the question is already a good start:
BookmarkablePageLink<Any, WebPage>("link", bookmark.page as Class<WebPage>)
Also fair is @AlexeyRomanov's intermediate variable (or a similar intermediate function):
val link: BookmarkablePageLink<Any> = BookmarkablePageLink("link", bookmark.page)
Also valuable for all who find this question via Google might be a short summary of Kotlin vs Java handling of type-variance as explained in Kotlin's documentation:
in
and out
keywords (which you can't use, because your declaration is in Java)Additionally, Java constructors at call-site only allow to specify type arguments from the class, while in Kotlin the constructor call has two type arguments: one from the class and the other from the constructor. So in Java, we have to say
new BookmarkablePageLink<T>("something", Page.class)
and in Kotlin
BookmarkablePageLink<T, Page>("something", Page::class.java)
despite both calling the same constructor with the same arguments.
Given that Kotlin chose an approach for variant types which is the exact opposite of Java's, I am still happy, that we only need workarounds in so few cases. ;-)
Please try
item.queue(BookmarkablePageLink<Any, WebPage>("link", bookmark.page))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With