Proguard stripes kotlin.Unit standalone object (in Kotlin runtime library), and that causes a compilation error if you are using this type. The following rule does not help with keeping this element (perhaps because Unit is not a class, it's an object):
-keep class kotlin.Unit.** { *; }
We use the Unit type like this:
fun assert(func : Assert.() -> Unit) = Assert().apply(func)
Is there a workaround for this issue or am I missing something?
In Progaurd rules, wildcards after the name of the class indicate nested classes. So get rid of the .** after Kotlin.Unit:
-keep class kotlin.Unit { *; }
Not directly relevant but if you use Kotlin's collections, you need to add the following Proguard rule as well:
-keep class kotlin.collections.CollectionsKt { *; }
Since Kotlin's Standard Library has its own Collections file and it contains top level functions and because files with top-level functions are not a direct Java class, you should use the name Kotlin conventionally uses to store this file as a Java class. From Kotlin's documentation:
All the functions and properties declared in a file example.kt inside
a package org.foo.bar are put into a Java class named
org.foo.bar.ExampleKt.
The name of the generated Java class can be changed using the #JvmName
annotation.
And again don't use the .** wildcard after the class name here.
Related
I've written myself into a corner where I want an instance of Class<Foo<Bar>>. While there's no apparent reason that this shouldn't be valid, there seems to be no way to create one. Foo<Bar>::class.java is a syntax error, and Kotlin does not provide a public constructor for Class.
The code I'm writing is an abstraction layer over gson. Below is an overly-simplified example:
class Boxed<T : Any> (val value: T)
class BaseParser<U : Any> (
private val clazz: Class<U>
) {
//This works for 98% of cases
open fun parse(s: String): U {
return gson.fromJson(s, clazz)
}
//Presume that clazz is required for other omitted functions
}
//Typical subclass:
class FooParser : BaseParser<Foo>(Foo::class.java)
// Edge Case
class BarParser : BaseParser<Boxed<Bar>>(Boxed<Bar>::class.java) {
override fun parse(s: String): Boxed<Bar> {
return Boxed(gson.fromJson(s, Bar::class.java))
}
}
// not valid: "Only classes are allowed on the left hand side of a class literal"
In my production code, there are already dozens of subclasses that inherit from the base class, and many that override the "parse" function Ideally I'd like a solution that doesn't require refactoring the existing subclasses.
Actually, there is a reason this is impossible. Class (or Kotlin's KClass) can't hold parameterized types. They can hold e.g. List, but they can't List<String>. To store Foo<Bar> you need Type (or Kotlin's KType) and specifically ParameterizedType. These classes are somewhat more complicated to use and harder to acquire than simple Class.
The easiest way to acquire Type in Kotlin is by using its typeOf() utility:
typeOf<Foo<Bar>>().javaType
Gson supports both Class and Type, so you should be able to use it instead.
The closest you'll get is Boxed::class.java. This is not a language restriction but a JVM restriction. JVM has type erasure, so no generic types exist after compilation (thats also one of the reasons generics cant be primitives, as they need to be reference types to behave).
Does it work with the raw Boxed type class?
For this case, it looks like
BaseParser<Boxed<Bar>>(Boxed::class.java as Class<Boxed<Bar>>)
could work (that is, it will both type-check and succeed at runtime). But it depends on what exactly happens in the "Presume that clazz is required for other omitted functions" part. And obviously it doesn't allow actually distinguishing Boxed<Foo> and Boxed<Bar> classes.
I'd also consider broot's approach if possible, maybe by making BaseParser and new
class TypeBaseParser<U : Any>(private val tpe: Type)
extend a common abstract class/interface.
In Java, we can create an utilities class like this:
final class Utils {
public static boolean foo() {
return false;
}
}
But how to do this in Kotlin?
I try using functions inside object:
object Utils {
fun foo(): Boolean {
return false
}
}
But when call this method from Java code it need to add INSTANCE. Ex: Utils.INSTANCE.foo().
Then I change to declare it as top-level function (without class or object):
#file:JvmName("Utils")
#file:JvmMultifileClass
fun foo(): Boolean {
return true
}
Then I can call Utils.foo() from Java code. But from Kotlin code I got Unresolved reference compiler error. It only allow be to use foo() function directly (without Utils prefix).
So what is the best approach for declaring utils class in Kotlin?
The last solution you've proposed is actually quite idiomatic in Kotlin - there's no need to scope your function inside anything, top level functions are just fine to use for utilities, in fact, that's what most of the standard library consists of.
You've used the #JvmName annotation the right way too, that's exactly how you're supposed to make these top level functions easily callable for Java users.
Note that you only need #JvmMultifileClass if you are putting your top level functions in different files but still want them to end up grouped in the same class file (again, only for Java users). If you only have one file, or you're giving different names per file, you don't need this annotation.
If for some reason you want the same Utils.foo() syntax in both Java and Kotlin, the solution with an object and then #JvmStatic per method is the way to do that, as already shown by #marianosimone in this answer.
You'd need to use #JvmStatic for that:
In Kotlin:
object Utils {
#JvmStatic
fun foo(): Boolean = true
}
val test = Utils.foo()
In Java:
final boolean test = Utils.foo()
Note that the util class you used in Java was the only way to supply additional functions there, for anything that did not belong to a particular type or object. Using object for that in Kotlin does not make any sense. It isn't a singleton, right?
The second approach you mentioned is rather the way to go for utility functions. Internally such functions get translated to static ones and as you can see they become the static util classes in Java you are searching for, as you can't have standalone functions in Java without a class or enum. In Kotlin itself however they are just functions.
Some even count utility classes to the anti-patterns. Functions on the other hand make totally sense without a class or object whose name hasn't so much meaning anyway.
The following Java code seems to be fine (no IDE errors),
List<Job> jobs = Job.listAll(Job.class);
When I copy-and-pasted, it was translated into,
val jobs = Job.listAll<Job>(Job::class.java)
But there was an error. Unresolved reference; listAll. What is the correct Kotlin equivalent?
The data class
import com.orm.SugarRecord
class Job : SugarRecord()
{
Sugar ORM: https://github.com/chennaione/sugar
This does not work because child class in Kotlin does not inherit static method from parent. (static does not exist in Kotlin)
You call the method like this:
SugarRecord.listAll(Job::class.java)
I am very new to Kotlin.
I want to be able to add a function to my abstract class, so when I define that function I will be able to invoke that on every child from that class(they inherit the abstract class)
However,I want to define those extension functions in other file.
I can't access those functions when i try to invoke them on a particular child implementation of the abstract class.
What are the rules, that I need to made to resolve my problem?
I want to by able achieve something like this:
abstract class Parent(val val1, val val2, val val3){}
class Child(var val1, var val2, var val3) : Parent(val1, val2, val3){}
class Child2(var val1, var val2, var val3) : Parent(val1, val2, val3){}
The extension method for parent and all childs:
fun Parent.convertToChild2( ): Child2? {
return //some creation method of Child2
}
And I want to be able to invoke this:
child: Child
child.convertToChild2
I defined all classes in separate file and also the extension function in other file.
I cannot access the function like this - is not visible.
The answer for my question, that satisfies me is just to extract the method to some "object" structure in other file and whenever we want to access that function we must import the path(package.object.method) to this.
But the problem is, that IDE is not propose me the path to my extension function - i must import it by myself.
I am using Android Studio 3 preview, hope this will be fixed.
UPDATE
It is better to define those function in just plain Kotlin file, so the functions will be not owned by any structure. Then it will be not a problem with importing those automatically by IDE from any place.
I believe that there is a misunderstanding here about extension functions. Extension functions are regular static functions that take in an instance of the receiver class as a parameter implicitly when you define the function and operate on it.
These static functions (aka extension functions) have some limitations.
They are not added to the class hierarchy so subclasses can not inherit them (if you define extension function for parent class you can't expect that method to be present in child class)
They don't have access to the private properties of the class that they are extending.
Also, they are resolved statically, for example (taken from here)
open class Shape
class Rectangle: Shape()
fun Shape.getName() = "Shape"
fun Rectangle.getName() = "Rectangle"
fun printClassName(s: Shape) {
println(s.getName())
}
printClassName(Rectangle())
This example prints "Shape", because the extension function being called depends only on the declared type of the parameter s, which is the Shape class.
First of all: There a many errors in your source code, you should fix before asking the question here (missing type annotations in constructors, missing val/var etc.).
To your question:
Normally, you can access extension functions even if defined in different kt files. Read the official docs covering extension scopes.
It's important to import your extension function
There is a way to do that:
fun <T: Parent> T.toChild2() {
TODO()
}
Child(...).toChild2()
I have multiple classes in one package. I am keeping all these classes with a single rule
-keep class com.something.folder.** { *; }.
How can I obfuscate one particular class from that package?
You can use an exclusion pattern like this:
-keep class !com.example.A,com.example.** { *; }
This will keep all classes in the package com.example and sub-packages, except for class com.example.A.
ProGuard will analyze the provided patterns in sequential order, and stop if it encounters a matching one. Thus you need to make sure that the exclusion pattern comes first.