21

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.

6
  • 2
    Do you have any top level functions/properties in ru.ifmo.ctddev.igushkin.dkvs package in tests? Commented May 27, 2015 at 11:34
  • How do you run the tests? Could you post your gradle config? It looks like the test package is compiled against the main package but is ran without it. Commented May 28, 2015 at 9:33
  • @SalomonBRYS, github.com/h0tk3y/dkvs/blob/master/build.gradle -- here it is. Commented May 28, 2015 at 12:51
  • @NataliaUkhorskaya, yes. I have a top level property. I'll try to remove it a little bit later. Commented May 28, 2015 at 12:58
  • @hotkey How do you run the tests ? Via an editor or via command line ? If the latter, which command ? Commented May 28, 2015 at 13:07

3 Answers 3

19

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. There's one more workaround which follows from what you said, I posted it as another answer.
Another side note to this solution; at least in Gradle, you need to run a clean build, or the test runner will still find the generated Package class.
5

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.

Comments

0

I faced similar issue when testing kotlin-native module, it was fixed by adding this dependencies:

testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.