Run single Kotlin file - intellij-idea

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.

Related

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

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.

Kotlin - IntelliJ cannot resolve the reference (from synthetic class)

I am using Kotlin and I have the kotlinc compiler plugin (using arrow-meta library) in place which changes the .class by adding for example new properties or new method etc during kotlin compilation time. for example, the original source Kotlin A.kt is like below
#MetaData
data class A (val x: String, val y: String)
after applying compiler plugin, the .class will be altered to (from source perspective), basically I will add implicitly MetaData into the primary constructor for all class so long as it is with annonation #MetaData in place, plus a new method fun getMetaData() generated
data class A(val x: String, val y:String, val myMeta: MetaData) {
fun getMetaData() {
//some logic check
return myMeta
}
}
now when it comes to use the new synthetic "class" manipulated as below, IntelliJ complains it cannot find resolve A (it has only the constructor with 2 parameters not 3) and cannot resolve the the synthetic method getMetaData() either.
val x = A("ba", "fo", MetaData(..))
val y = x.getMetaData()
can somebody shed some light on it?
I know lombok seems no problem with it after adding its #Getter annotation for example into Java source code, IntelliJ can recognize its getXXX method (which is generated by lombok).
I don't know how to implement the same for my case for kotlin language. please include the detailed steps if possible.

Kotlin - How to be able to run and test function?

I am creating demo code in Kotlin. I am trying so students should be able:
run function itself
run test
For example:
If function is created in .kt file, outside of class:
fun main(){
print("Hello world!")
}
it can be run
but I could not find the way to call it from the test
If the function is inside the class:
class Hello {
fun main(){
print("Hello world!")
}
}
the function can be called from the test
but can not be run - the green "Run" button is not visible.
Question: How to make such a function can be run manually and by test at the same time?
I'll assume you are writing your tests in Java, because if it's in Kotlin, calling main is trivial: main(), provided that you have imported the package/in the same package.
Kotlin global functions are compiled into static methods of a class with a name similar to the Kotlin file in which the function is declared, suffixed with Kt For example, if the file is called "app.kt", the class name would be AppKt. So if you declared main in app.kt, you would call:
AppKt.main();
in Java
You can change this name by annotating the Kotlin file with #JvmName:
#file:JvmName("MyOwnName")
Then you can call:
MyOwnName.main();
in Java.
See more documentation here

Create a Gradle function for dependencies block in Kotlin

Currently, I'm creating a function, which is available for the dependencies block in Groovy with:
project.dependencies.ext.foo = { String value ->
project.files(extension.getFooDependency(project).jarFiles).asFileTree
}
Thanks to that, I'm able to do:
afterEvaluate {
dependencies {
compileOnly foo('junit')
}
}
I'm converting the Groovy code to Kotlin, and I'm wondering how to rewrite this foo extension.
I've ended up with:
project.dependencies.extensions.extraProperties.set("foo", Action { value: String ->
project.files(extension.getIdeaDependency(project).jarFiles).asFileTree
})
After calling foo('junit'), I get the following exception:
> Could not find method foo() for arguments [junit] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
I do not think that would work the same way in Kotlin DSL. Instead, you may declare a Kotlin extension function somewhere in the project. Then calling it would include all necessary receivers to you.
For multiple projects, I would recommend using a buildSrc project. Declarations there are visible to all project files below.
Speaking about Groovy and Kotlin support, I would do something like that:
private fun getFooImpl(scope: getFooImpl, name: String) { /*here is the implementation */ }
fun DependencyHandlerScope.getFoo(name:String) = getFooImpl(this, name)
//in Groovy
project.dependencies.extensions.extraProperties.set("foo", {getFooImpl(..)})
The same code could fit into a plugin as well. A more generic way could be to register a custom DLS extension, so to allow a custom block-like thisIsMyPlugin { .. } in the Gradle DSL and define all necessary helper functions in the extension class. Here the downside is in forcing users to wrap their code into the thisIsMyPlugin block.

kotlin : cannot parse string to enum with Jackson

I use the lib jackson-module-kotlin to parse string of json into object.
My issue is when I parse a string into an enum , and when I launch with intellij, I have this stack trace:
Caused by: kotlin.reflect.jvm.internal.KotlinReflectionInternalError:
Reflection on built-in Kotlin types is not yet fully supported. No
metadata found for public final val name: kotlin.String defined in
kotlin.Enum[DeserializedPropertyDescriptor#212b316a]
I don't have this issue when I launch with maven.
I use kotlin 1.1.51, with intellij kotlin plugin 1.2.0-release-IJ2017.3-1, I target a JVM 1.8, and i use jackson-module-kotlin version 2.8.7
what should I do?
enum class CType { DEAL, FILE }
data class Code(val code: String, val type: CType)
fun testDeserialization() {
val mapper = jacksonObjectMapper()
// following line throws an exception:
mapper.readValue("""{"code":"A","type":"DEAL"}""", Code::class.java)
}
The only way I got it working is by adding additional #JvmStatic annotation. I had mapper.registerModule(new KotlinModule()); and all, nothing worked but this:
package nc.features.algo.model
import com.fasterxml.jackson.annotation.JsonCreator
import com.fasterxml.jackson.annotation.JsonValue
enum class LHStatus (
#get:JsonValue val code: Int
) {
LH_POS_OVU_WAITING(1),
LH_NEG_OVU_WAITING(2),
;
companion object {
#JsonCreator
#JvmStatic
fun deser(code: Int?): LHStatus? {
if (code == null) return null
for (i in values()) {
if (i.code == code) return i
}
return null
}
}
}
You have to do a few things.
Update Jackson dependencies to the latest version (right now, 2.9.4).
Update Kotlin version to a version equal or greater than 1.3.0.
Be sure to add the following dependencies to your build.gradle:
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:$jackson_version"
... then you call registerKotlinModule() on your Jackson ObjectMapper and the code of your enum should be just like this:
enum class CType(#get:JsonValue val value: String) {
DEAL("deal"),
FILE("file");
companion object {
#JsonCreator
fun fromString(value: String): CType? {
for (type in CType.values()) {
if (type.name.equals(value, true)) {
return gender
}
}
return null
}
}
}
Intellij is most likely using the kotlin compiler version 1.2.0 (from the plugin) and it doesn't seem to support reflection properly.
I suggest you do one of the following:
Upgrade your kotlin version in maven and the intellij kotlin plugin to newer versions (e.g. 1.2.30). If you do that, you also have to update jackson-module-kotlin to >= 1.9, since there is an incompatibility with kotlin 1.2 (see here).
Set the kotlin compiler version to 1.1 in Intellij Idea settings.
It is generally a good idea to use the same version of kotlin in Intellij Idea and maven/gradle.
You need to use the Kotlin module for Jackson that is compatible with Kotlin 1.2.x, this includes minimally these three versions of the module:
2.9.4.1 (works with any 2.9.x of Jackson, but best to use most recent)
2.8.11.1 (for Jackson 2.8.x)
2.7.9.1 (for Jackson 2.7.x)
Otherwise, you will run into a problem with library mismatches.
The jackson-module-kotlin homepage lists these as the current versions, but they are likely to change and you can check the various Maven repository search engines to see which library versions are available and which dependencies they have on Kotlin to find matching versions.
Also note you can import the extensions for the ObjectMapper class and use reified types, so instead of:
val something = mapper.readValue("""{"code":"A","type":"DEAL"}""", Code::class.java)
you would have:
val something: Code = mapper.readValue("""{"code":"A","type":"DEAL"}""")
or alternatively:
val something = mapper.readValue<Code>("""{"code":"A","type":"DEAL"}""")
It is usually bad to use the erased type (i.e. Whatever::class.java) since this does not work for anything with generic type parameters, and using reified types also works nicely when deserializing into collections.