Kotlin compile error "unresolved reference" only when compiling from command line - kotlin

I have the Kotlin code:
import com.google.gson.Gson
import java.io.File
class System {
/*
Save current game state to file
*/
internal fun saveGameState(game: Game) {
val gameState = game.getGameState()
val gson = Gson()
val jsonString = gson.toJson(gameState)
val pathname = FILENAME_SAVED_GAME
File(pathname).writeText(jsonString)
}
private fun loadGameState(): Game {
val jsonString = File(FILENAME_SAVED_GAME).readText(Charsets.UTF_8)
val gson = Gson()
val gameState: GameState = gson.fromJson(jsonString, GameState::class.java)
File(FILENAME_SAVED_GAME).delete()
return Game(gameState)
}
...
}
When I run it from within IntelliJIDEA, it compiles and runs fine, including using this class to save state and restore state.
When I compile it from the command line, I use this command:
kotlinc *.kt -include-runtime -d GizmosK.jar
and I this error message:
System.kt:1:12: error: unresolved reference: google
import com.google.gson.Gson
^
System.kt:11:20: error: unresolved reference: Gson
val gson = Gson()
^
System.kt:19:20: error: unresolved reference: Gson
val gson = Gson()
^
I've successfully used this command many times before, but possibly not since adding this System class, which is the only one that imports anything from outside my project.
I've searched, and found this question which appears very similar to my problem, but I have a few concerns.
First, I don't know if this solution applies to my situation since my code is pure Kotlin and not Android.
Second, I don't know how to generalize their solution and make it apply to my situation. Like, I know I probably have to replace something with google.gson or com.google.gson or com.google.gson.Gson in there somewhere, but I don't know where, since there are three things there that look like package names. Do I need all three? I also don't know if expressions like package_name are literal strings I should enter verbatim or if I should replace those words with the actual package name.
Third, I've never had to specify flovar/flavor nor resource_package before in a command line, and I don't want to introduce new variables, if at all possible.
BTW, I'm compiling from the command line to generate a .jar file to distribute so anyone can run it from the command line without sharing my code or requiring they install IntelliJ IDEA.

Related

Kotlin class won't let me extend abstract class from different file

I am working on an object-oriented project, and I want to improve my understanding of the OOP part of Kotlin. I have the following abstract class:
package Objecttest
abstract class Abstractclasstest {
abstract fun testString(s: String): String
}
Now I want to extend it in a new class in a different file like this:
package Objecttest
public class Newclasstest : Abstractclasstest() {
override fun testString(s: String): String {
return s
}
}
but when I try compiling Newclasstest.kt, I am met with the following error message: "error: unresolved reference: Abstractclasstest".
Folder structure:
Objecttest/
├── Abstractclasstest.kt
├── Newclasstest.kt
Why is this and how can I work around it? The most important bit is why, because I want to avoid the same mistake in the future.
It seems to me that you need to compile Abstractclasstest.kt first using kotlinc Abstractclasstest.kt and only then compile Newclasstest.kt as follows: kotlinc -cp . Newclasstest.kt. This will search for class files in the same path as Newclasstest.kt on which it should already find the one corresponding to Abstractclasstest.kt. Or you can just compile the 2 files at the same time using kotlinc *.kt.

Kotlin class in other package not resolved

I started with Kotlin and want to exclude files in other packages in Visual Studio Code. Unfortunately it does not work
Person.kt
package com.example
public class Person(
val _firstName: String,
val _lastName: String,
val _age: Int
)
main.kt
import com.example.Person
fun main(args: Array<String>) {
val person = Person("Peter","Pan",12)
println(person)
}
When I hover over in the main function Visual Studio Code show me the Person class, thus it seems that it is recogniced but as far as I run the code I get the following error
[Running] cd "c:\Users\Matthias\Desktop\Kotlin\" && kotlinc Main.kt -include-runtime -d Main.jar && java -jar Main.jar
Main.kt:1:12: error: unresolved reference: example
import com.example.Person
^
Main.kt:4:18: error: unresolved reference: Person
val person = Person("Peter","Pan",12)
^
I played around with other package names like "domain" but then the whole class is not found. I put them in folder but the error stays the same.
Since you are compiling only Main.kt, it doesn't include Person in the Main.jar being built for running. As you are referring to Person in the code, it should be part of the jar.

Run single Kotlin file

I have two Kotlin files in the same folder:
Both files have a trivial main method.
I can right click on helloworld.kt file and select "Run..." from the menu.
There's no such option for the circle.kt file though.
This is my run/debug configuration for helloworld.kt:
I tried to create an equivalent configuration for circle.kt, but it complains that the class com.example.kotlin.learning.CircleKt has no main method:
There's actually no class in that file. But there isn't one in HelloWorld.kt as well, and that works.
Here's the code for helloworld.kt:
package com.example.kotlin.learing
fun main (argomenti: Array<String>) {
println ("SUCA!")
println (saluta ( "mario"))
val vettore : Array<String> = arrayOf("pippo", "pluto", "paperino")
println(vettore [0])
}
fun saluta (chi : String) = ( chi + " antani" )
here's circle.kt:
package com.example.kotlin.learing
fun main() = println("pippuz!")
I realize I am missing something deep here. What is that?
Thanks
If I'm not mistaken, main method without parameters is supported from Kotlin version 1.3-RC. Which version of Kotlin are you using?
If you are using an older version of Kotlin, you should pass an array of Strings as the argument of the main method.

Kotlin support for JDBI SqlObject gives UnsupportedOperationException

Extending the Kotlin equivalent of the Dropwizard JDBI3 setup listed in the official Dropwizard documentation, I fail to get automatic parameter binding without #Bind and the Kotlin-specific mapping magic for JDBI to work as shown in Kotlin support for SqlObject. Instead of this...
data class Thing(val id: Int, val name: String,
val nullable: String?,
val nullableDefaultedNull: String? = null,
val nullableDefaultedNotNull: String? = "not null",
val defaulted: String = "default value")
interface ThingDao {
#SqlUpdate("insert into something (id, name) values (:something.id, :something.name)")
fun insert(something: Thing)
#SqlQuery("select id, name from something")
fun list(): List<Thing>
...
}
..I always have to do:
interface ThingDao {
#SqlUpdate("insert into something (id, name) values (:id, :name)")
fun insert(#Bind("id") id: Int?, #Bind("name") name: String)
#SqlQuery("select id, name from something")
fun list(): List<Thing>
...
}
Gradle has these JDBI-specific settings:
...
compile "io.dropwizard:dropwizard-jdbi3:1.3.5"
compile "org.jdbi:jdbi3-sqlobject:3.3.0"
compile "org.jdbi:jdbi3-postgres:3.3.0"
compile "org.jdbi:jdbi3-kotlin:3.3.0"
compile "org.jdbi:jdbi3-kotlin-sqlobject:3.3.0"
....
The Dropwizard application has the following run configuration:
override fun run(configuration: MyConfig, environment: Environment) {
val factory = JdbiFactory()
val jdbi = factory.build(environment, configuration.database, "postgresql")
// This is said to install all available plugins and is thus redundant.
// I have tried to include various combinations of the following in
// some desperation. None work.
jdbi.installPlugins()
jdbi.installPlugin(SqlObjectPlugin()) // This...
jdbi.installPlugin(KotlinPlugin())
jdbi.installPlugin(KotlinSqlObjectPlugin()) // ..and this alone are said to do the job
...
Otherwise, everything seems to run just fine with custom UUID mappings, Jackson Kotlin data object mapping and such.
The result of using :something.id in particular always is:
java.lang.UnsupportedOperationException: No argument factory registered for 'Thing(...'
The solutions suggested in the comments all work. Thanks very much! The trouble seemingly arose in an unfortunate sequence of adding the right libraries and fixing the code in a process that left the impression of things not working (I am still not a fan of annotation-mania).
Summary for anyone that might find anything useful in it:
Adding #BindBean made data classes work as arguments indeed.
Leaving out #Bind for arguments apparently worked for quite a while, which I just didn't notice...
..possibly in parts as I incorrectly tried to use it with data classes, too: #Bind("something") something: Thing instead of the correct (but still unnecessary) #BindBean("something") something: Thing
Given this, removing #Bind and #BindBean worked (at least with the 1001st gradle clean build).
I removed compile "org.jdbi:jdbi3-sqlobject:$jdbi_version", which either way doesn't seem to have any effect on things working properly (as Dropwizard is said to reference it already).
For the record, these are the dependencies that seem to work for me right now:
buildscript {
ext.kotlin_version = '1.2.51'
ext.dropwizard_version = '1.3.5'
ext.jdbi_version = '3.3.0'
...
}
...
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "io.dropwizard:dropwizard-core:$dropwizard_version"
compile "io.dropwizard:dropwizard-jdbi3:$dropwizard_version"
compile "io.dropwizard:dropwizard-auth:$dropwizard_version"
compile "io.dropwizard:dropwizard-views-freemarker:$dropwizard_version"
// This is to serve static content from resources/static
compile "io.dropwizard:dropwizard-assets:$dropwizard_version"
compile 'com.fasterxml.jackson.module:jackson-module-kotlin:2.9.4'
compile 'com.fasterxml.jackson.module:jackson-modules-java8:2.9.4'
// Removed as redundant
// compile "org.jdbi:jdbi3-sqlobject:$jdbi_version"
compile "org.jdbi:jdbi3-postgres:$jdbi_version"
// So, these are still required as Dropwizard doesn't know Kotlin
compile "org.jdbi:jdbi3-kotlin:$jdbi_version"
compile "org.jdbi:jdbi3-kotlin-sqlobject:$jdbi_version"
// Database
compile 'org.postgresql:postgresql:42.1.4'
// ...
testCompile "io.dropwizard:dropwizard-testing:$dropwizard_version"
// ...
}

How to use DeprecationLevel.ERROR

Let's say I am writing a library and have a class that looks something like this (contrived example, but shows self reference:
import java.util.logging.Logger
class MyClass(private val myNum: Int) {
companion object {
private val LOG = Logger.getLogger(MyClass::class.java.canonicalName)
}
constructor() : this(1337)
fun addTo(num: Int): Int {
LOG.fine { "Adding num $num to $myNum" }
return myNum + num
}
fun doubleAdd(num: Int): Int = 2 * addTo(num)
}
Now, I have decided that I want to deprecate this class and have my consumers move on to to better things, so I give them a warning.
#Deprecated("Don't use!", level = DeprecationLevel.WARNING)
class MyClass(private val myNum: Int) {
// ...
}
Now, after some more time I'd like to increase the strictness with my deprecation. I still want the library to be binary compatible, so I do not remove the code I see that there is the DeprecationLevel.ERROR available, so I try to use it.
#Deprecated("Don't use!", level = DeprecationLevel.ERROR)
class MyClass(private val myNum: Int) {
// ...
}
Except now, when I try to compile my own project, I get compiler errors:
e: /path/to/project/src/main/kotlin/MyClass.kt: (7, 44): Using 'MyClass' is an error. Don't use!
e: /path/to/project/src/main/kotlin/MyClass.kt: (10, 23): Using 'MyClass' is an error. Don't use!
This is on both the MyClass reference and the this primary constructor reference.
What is the point of DeprecationLevel.ERROR? If I am using it wrong, what is the intended use, and how do I use it?
NOTE: This whole example was done with Kotlin 1.2.21
It does exactly what is described in the documentation: DeprecationLevel
ERROR means usage of that code generates an error in the compiler. This is when you know using the code is going to cause problems and you'd rather crash the compilation, even if that code compiled fine previously.
There is also the HIDDEN deprecation level which does what you describe. It 'hides' the annotated element from the compiler but leaves it in the binary output. This will still cause a compilation error in your project because it is meant for binary compatibility, not newly compiled code.