Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin: java.lang.NoSuchMethodError in tests

Is it possible to use Kotlin package functions and package properties in different sourcesets? When I try to do so, I have NoSuchMethodError thrown.


Example

I have Gradle project with Kotlin code and two sourcesets in it, main and test. In main, I have the following code in one of the files:

package ru.ifmo.ctddev.igushkin.dkvs
...
public val payloadSplitter: String = " ### "

In test I try to access payloadSplitter with the following code:

package ru.ifmo.ctddev.igushkin.dkvs
...
public class MessageTests {
    ...
    test fun testParsing() {
        ...
        checkParseAndToString("p1b 345 ${payloadSplitter} set a b c")
    }
    ...
}

And exactly in the first line where payloadSplitter is accessed, at runtime I get

java.lang.NoSuchMethodError: ru.ifmo.ctddev.igushkin.dkvs.DkvsPackage.getPayloadSplitter()Ljava/lang/String;

Other global variables and functions are also inaccessible in test with the same error.


UPD Kotlin team explained the issue and announced the fix here.

like image 629
hotkey Avatar asked May 25 '15 21:05

hotkey


2 Answers

For properties and methods outside of classes, Kotlin creates a java class named ${packagename}Package with the properties and methods implemented as static methods and variables. With multiple source-sets, the java class will be created twice, once for each source-set. Your issue is that the test source-set "package class" is hiding the class compiled in the main source-set.

As mentioned in the comments above, avoid having any top-level properties or methods in the test source-set to prevent the Kotlin compiler from creating this package class in the test output directory.

like image 138
Travis Avatar answered Oct 21 '22 08:10

Travis


In addition to what was suggested earlier, I found another workaround: if you need package-level functions or properties in test just move the tests to different package, e.g. in your test sources:

 package ru.ifmo.ctddev.igushkin.dkvs.tests

and then do

 import ru.ifmo.ctddev.igushkin.dkvs.*

which is everything from your main package. This will make Kotlin compliler generate two non-conflicting Package classes, therefore both can have global members.

like image 41
hotkey Avatar answered Oct 21 '22 09:10

hotkey