Kotlin-allopen plugin + #JvmField on a val not final enough - kotlin

I am testing a new kotlin-allopen and kotlin-spring plugins under Kotlin 1.0.6.
In one of my #Transactional-annotated classes I have a field:
#JvmField val foo = null
When I try to build the project, I get:
Error:(45, 5) Kotlin: JvmField can only be applied to final property
Is there any proper way of dealing with this? My real-life code needed #JvmField because of the JUnit's #Rule. Managed to "solve" the problem by removing a #JvmField and annotating a getter instead. Not sure if a bug or a feature.

I got the official solution.
In such case, finality provided by val is not enough. It turns out you need explicitly add final keyword there and this is not considered a bug.
#JvmField final val foo = null

Related

Best way to define model using AndroidAnnotations #Rest and Kotlin?

I am totally new to Android and Kotlin and I was looking into Android Annotations.
I managed to decode a JSON response using the following code:
class ExampleModel {
#JvmField
final var id: Int = 0
lateinit var title: String
var description: String? = null
var author: Author? = null
}
#Rest(
rootUrl = "...",
converters = [MappingJackson2HttpMessageConverter::class]
)
interface ExampleClient {
#Get("/promotions")
fun getModels(): List<ExampleModel>
}
Now it does work but there are a couple of questions I'd like to ask.
Is it possible to use data classes? I tried but I kept getting an error from MappingJackson2HttpMessageConverter saying that there was no constructor available.
Is it somehow possible to just ignore extra keys that might appear in the JSON? Let's say that I am not interested in the author data for now, is there a way to just remove its declaration without having the decoding fail with "unexpected key"?
Consider that I usually work with Swift so if you could point me to the "Codable" equivalent in Kotlin I would really appreciate it.
Cheers
Kotlin Data classes don't have default constructor which is usually required by json deserialization libraries. Any data class require at least one constructor argument, but you can work around it. Define default values, you can use null. For example:
data class Pojo(val name: String? = null, val age: Int? = null)
Such code will allow to use Pojo() constructor. It should work, but it's better to use json deserializer that is more kotlin native or generate data classes with AutoValue.
Jackson that you're using here allows to ignore fields with #JsonIgnoreProperties.
If you're learning Android, don't start from Android Annotations if you don't have to. It's not very popular or modern solution. I used it in few projects back in the day, those were very difficult to maintain or to introduce new developers. Look into android architecture components and jetpack - google made few nice code labs. Also for json pick Moshi or Gson.

Using kotlin expression annotations

Kotlin allows to annotate expressions. It is however unclear, how such annotations may be useful and how to use them.
Let's say in following example I would like to check, that string contains number specified in #MyExpr annotation. Can this be achieved and how?
#Target(AnnotationTarget.EXPRESSION)
#Retention(AnnotationRetention.SOURCE)
annotation class MyExpr(val i: Int) {}
fun someFn() {
val a = #MyExpr(1) "value#1";
val b = #MyExpr(2) "value#2";
}
Specifying #Target(AnnotationTarget.EXPRESSION) is just a way of telling the compiler where the user of the annotation can put it.
It does not do anything on it's own rather than that.
So e.g.
#Target(AnnotationTarget.EXPRESSION)
#Retention(AnnotationRetention.SOURCE)
annotation class Something
// compiler will fail here:
#Something class Foo {
// but will succeed here:
val a = #Something "value#1"
}
Unless you're writing an Annotation Processor (so a thing that looks for Annotations and does something with them), your annotations have just informational value. They are just a signal to other devs (or future You) of something.
#Target(AnnotationTarget.EXPRESSION)
#Retention(AnnotationRetention.SOURCE)
annotation class UglyAndOldCode
val a = #UglyAndOldCode "this is something old and requires refactoring"
If you want to implement what you've stated in your question you would have to create an Annotation Processor that checks expressions marked with MyExpr for the condition that you've specified.

What's Kotlin equivalent of Class<?>

I want a map between Int and any class. In Java it would be Map<Class<?>, Integer>. What's the Kotlin equivalent of that?
KClass is Kotlin's equivalent to java.lang.Class.
An instance of KClass can be obtained with ::class on either a type or a value (i.e. String::class, 3.8::class).
If you require a Java Class instance from a KClass you can use the java extension property:
val kotlinClass: KClass<String> = String::class
val javaClass: Class<String> = String::class.java
Keep in mind that if you want to use kotlin-reflect's full features you will need kotlin-reflect on the classpath.
So in your case, the equivalent would be Map<KClass<*>, Int>.
The equivalent declaration would be Map<Class<*>, Int>.
You're looking for KClass. You need to add the Kotlin reflection library in order to use it.

Using lateinit primitives wrappers

I've got something like that:
#LocalServerPort
private lateinit var serverPort: Integer
And IDEA warns that java.lang.Integer should not be used, use kotlin.Int instead. But kotlin.Int cannot be used with a lateinit property. Is there a way to satisfy both restrictions?
Update: I'm compiling with -Werror, as I think every project should. Therefore, code becomes ridden with #Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") adding unnecessary garbage.
Yes there is, Delegates.
#LocalServerPort
private var serverPort by Delegates.notNull<Int>()
Delegates are computationally slightly more expensive than lateinit. I use lateinit where I can, otherwise I use the method above. The code above will present exactly the same as lateinit ie. no null check needed.

Kotlin JUnit Rules

In Kotlin M13, this was an acceptable way to create a JUnit rule:
#Rule #publicField val temp = TemporaryFolder()
Now that #publicField has been deprecated, how else can this be achieved? The IDE hint suggests replacing #publicField with lateinit, but lateinit val's are no longer allowed, and I'm not sure this would help even if they were.
The answer as of Kotlin 1.0 is as follows:
#Rule #JvmField val temp = TemporaryFolder()
#JvmField exposes the backing field with the same visibility as the property, ergo a public field for the JUnit rule to use.
If anyone stumble's on this. I believe the approach with JJunit5 would be using #TempDir.
https://junit.org/junit5/docs/5.4.2/api/org/junit/jupiter/api/io/TempDir.html
If you would need share the TempDir with tests, it must be a static property of the class. Static for java or within a companion Object for Kotlin
Just guessing, but the following might work (with var):
#Rule lateinit var temp = TemporaryFolder()
I would try asking at kotlin's slack http://t.co/xpQXUKaDvP
Currently it's the fastest way to fix anything.