External annotations & extending ThreadPoolExecutor


#1

I can't figure out how to extend ThreadPoolExecutor.

It says I have to re-implement some of the methods (I assume it’s because of the @NotNull annotations)
I figured out the syntax to forward some of the them to the super class:

  public override fun awaitTermination(timeout: Long, unit: TimeUnit): Boolean {
  return super<ThreadPoolExecutor>.awaitTermination(timeout, unit: TimeUnit?)
  }

I am running into troubles when generics are involved though. This doesn’t work:

  public override fun <T> invokeAny(tasks: Collection<out Callable<T>>): T? {
  super<ThreadPoolExecutor>.invokeAny(tasks: Collection<out Callable<T>?>?)
  }

Is there a way to write it correctly or is it simply a bug?


#2

This is an inconsistency in external annotations: not all the classes in the hierarchy are annotated the same way.

THere are two possible workarounds:

  1. Annotate ThreadPoolExecutor and all of its direct and indirect base classes consistently
  2. Use “as” instead of “:” to cast the arguments


This problem will go away soon when we teach the compiler to propagate type information through the hierarchy


#3

Using as (and as?) was the first thing I tried (I reverted to : when Idea complained that the cast was not necessary and suggested using : instead). I could not get the syntax right though. Idea kept complaining that I couldn't call abstract methods from the super class.

Maybe I didn’t get the syntax with as quite right.
Would you mind showing how you would write that invokeAny method? (returning super(Collection<out Callable<T>?>?))


#4

Looks like I was wrong: the as-trick doesn't work either, so the right way is to annotate ThreadPoolExecutor:

  • Navigate to the declaration of invokeAny() method (no matter whether you have sources attached or not)
  • It will be in the ExecutorService class
  • Click on the Kotlin icon in the gutter to the left of the editor
  • Copy the signature: fun <T> invokeAny(tasks : Collection<out Callable<T>>) : T?
  • Go to ThreadPoolExecutor's invokeAny, press Alt+Enter and Choose "Specify Custom Kotlin signature"
  • Put what you copied there
  • Now you can remove the casts from invokeAny() imlementation in your class

To see more about annotations, please refer to this page: http://blog.jetbrains.com/kotlin/using-external-annotations/

After completing this, feel free to submit the changes in your annotations as a pool-request to Kotlin


#5

The problem is that invokeAny's implementation is not in ThreadPoolExecutor but in AbstractExecutorService. And when I try to add custom annotations to this abstract class, I get an exception: Couldn't find function descriptor for invokeAny in java.util.concurrent.AbstractExecutorService

I’ve submitted an issue on youtrack: http://youtrack.jetbrains.com/issue/KT-2935


#6

As a workaround I created an intermediate java class extending ThreadPoolExecutor, and annoted that one (custom kotlin signatures and @NotNull). In kotlin, I could then extend that one rather than ThreadPoolExecutor directly.


#7

I can't reproduce this. Please, make sure you are running up-to-date Kotlin (M3.1) and IntelliJ IDEA (122.159).


#8

I was running 3.1 with 122.519. I did a little digging since then (I updated the issue on youtrack with my findings as well). After detaching the sources from the sdk setup, then it started to work. Event after re-attaching the sources.


#9

Hm. We'll look for similar cases to investigate. Thanks