Kotlin get class name in Annotation processor - android

I am creating Annotation processor with annotation that takes class names, check if the name is CamelCase and writes all the classes which don't use camelcase.
This is the function which writes all those classes:
private fun checkCamelVariable(classElement: TypeElement) {
classElement.enclosedElements.filter {
!it.simpleName.toString().isDefinedCamelCase()
}.forEach {
printWarning("Detected non-camelcase name: ${it.simpleName}.")
}
}
In my build log i get:
warning: Detected non-camelcase name: TAG.[WARN] Incremental annotation processing requested, but support is disabled because the following processors are not incremental: com.example.processor.GenerateProcessor (NON_INCREMENTAL), com.google.auto.service.processor.AutoServiceProcessor (NON_INCREMENTAL).
Which means my annotation is working but I can not get the class names.
Looked on places like this: How to get rid of Incremental annotation processing requested warning?
but none of suggestions helped me.

Related

Kotlin automatically changes parameter names in release build

Json object's field name automatically changing in release build and causing api to fail.
Data Object :
data class SleepStage(val awake:Double, val light: Double, val rem:Double, val deep:Double)
IN DEBUG MODE
SleepStage": {"awake": 0.58,"light": 4.23,"rem": 1.28,"deep": 0.35 }
IN RELEASE MODE:
SleepStage": {"a": 0.58,"b": 4.23,"c": 1.28,"d": 0.35 }
This is called obfuscation. When you create a release version, Proguard shortens all variable names.
Check out this StackOverflow post:
Proguard - do not obfuscate Kotlin data classes
It should be enough to add a #Keep annotation to your class:
#Keep
data class SleepStage(
...
)

Kotlin Jacoco coverage not showing for static methods (companion) in Android

I implemented Jacoco in my Android project using the following tutorial https://proandroiddev.com/unified-code-coverage-for-android-revisited-44789c9b722f to cater for test coverage in the kotlin classes.
For some unknown reason, it's not reporting coverage for static methods declared under the Companion block.
class Meh {
companion object {
fun test () {
// logic to test
}
}
However if I convert the class to an instance rather than a singleton that I am able to see the coverage completely fine.
Has anyone came across this problem ? and what did you do ?
following tutorial https://proandroiddev.com/unified-code-coverage-for-android-revisited-44789c9b722f
after cloning of example from the same tutorial in its state as of today (HEAD commit)
git clone https://github.com/rafaeltoledo/unified-code-coverage-android.git
cd unified-code-coverage-android
git checkout kotlin-coverage
addition of companion object into MainActivity
class MainActivity : AppCompatActivity() {
+ companion object {
+ fun executed() {
+ }
+
+ fun notExecuted() {
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+ executed()
start of virtual device Pixel XL with API 28 and target Android 9.0 (Google APIs) in freshly downloaded Android Studio 3.2.1
and execution of
./gradlew jacocoTestReport
following report is produced in directory app/build/reports/jacoco/jacocoTestReport/html/ as expected
Given the amount of factors that influence result (such as versions of all involved components - Android SDK, Device, Kotlin compiler, Gradle, JaCoCo, etc, etc), attempts to guess what is different in your case are IMO counterproductive, and so that the best advice - is to perform very careful comparison of differences between your setup and above example.
Update
As was figured out during comparison by #HeWhoProtects , problem was in
exclusion of **/*$*
that refers to exclusion of class files from analysis. Single source file can compile into multiple class files, e.g. in case of nested classes in Java and exactly in case of companion in Kotlin and in both cases name of class and class file will contain $.
I found the the cause of the problem but not sure why it caused it yet, my excludes rules includes more rules than the one in the tutorial above, in different jacoco tutorial for ignoring autogenerated files, it was suggested to include '**/*$*' as rule, as soon as I removed it, it showed coverage for static methods in kotlin.
My understanding of Jacoco that these rules ignore files and will not show it in the report, and before I made the change, it was showing that this class is covered in the test coverage.... is it weird or am I missing a fundamental thing about how kotlin generates methods or how jacoco excludes rules work ?
Anyway I hope this helps..

Lobok #AllArgsConstructor throw exception when app start on Android 4.2

I have model
#Data
#AllArgsConstructor
#NoArgsConstructor
public class ProductsRequest {
private String initiatorType;
private String categoryCode;
I have lombok config:
lombok.anyConstructor.suppressConstructorProperties = true
lombok.addGeneratedAnnotation = false
On android with API 27(Android 7 on real device) all work fine. On android 17(Android 4.2 on emulator) In this line I get error:
return restApiFactory.getProductService().getProducts(productsRequest);
error:
Caused by: java.lang.ClassNotFoundException: Didn't find class "java.beans.ConstructorProperties" on path: /data/app/my-1.apk
If I change
#AllArgsConstructor
#NoArgsConstructor
to standart constructors - all work fine
Because I never experienced such issue with ctor-s I encourage you to describe your problem in more detail. I assume the code you manually wrote somehow differs from the code lombok generated. Might be the visibility of methods or some special annotation added.
Using delombok feature (https://projectlombok.org/features/delombok) you will expand the annotations to real code. Than you can diff your manually written code and lombok generated code. So you can explore if #java.beans.ConstructorProperties added or not above the code lombok generated. (Delombok using Gradle)
Note: Actually you will have 3 ctor: #AllArgsConstructor, #NoArgsConstructor and #RequiredArgsConstructor is implicitly covered in #Data.
Based on your lombok.config file, ctor-s should not have an annotation. Could it be that some of your flavors are missing the lombok.config on class path?

How can I obfuscate my sdk coded with kotlin (and get rid of Metadata)

I'm developing a SDK (Android library), and I have to obfuscate a large part of my code so the customer may not try and play with internal code.
My lib is coded in kotlin, and I used proguard to obfuscate the code. Problem is that there are still #kotlin.Metadata (runtime) annotations inside the code after compile and obfuscation. With those annotations, it's really easy to retrieve the java code that originated this "(not-so-)obfuscated" bytecode.
I first thought it was my fault, and my project had too many entropy sources that might have induced this behaviour, so I made a sample project to prove that the problem does not come from my sdk implementation.
I created a new project with AS, then a lib module with 2 files:
facade.kt is my facade class, the one that I do not wish to obfuscate, so the customer may use it:
package com.example.mylibrary
class MyFacade(val internalClass:InternalClass) {
fun doSomething() {
internalClass.doSomething(
firstArgument=1,
secondArgument=2
)
}
}
and in this sample, internal.kt holds the classes that I want to obfuscate:
package com.example.mylibrary
class InternalClass {
fun doSomething(firstArgument: Int, secondArgument: Int) {
System.out.println("Arguments are : $firstArgument, $secondArgument")
}
}
The proguard rules are injected into gradle project with this release closure:
buildTypes {
release {
minifyEnabled true
proguardFiles 'proguard-rules.pro'
}
}
And here is proguard-rules.pro (only one line, nothing more) :
-keep class com.example.mylibrary.MyFacade {*;}
The result: when I ./gradlew clean myLib:assembleRelease, I do obtain an aar in which my facade is kept, and my internal class has been renamed in 'a', with one method 'a', except that the class is still annotated with kotlin #Metadata, which holds every information that helps the decompiler retrieve the original class name, the method, attribute and argument names, etc...
So my code is not so obfuscated at all...
#Metadata(
mv = {1, 1, 7},
bv = {1, 0, 2},
k = 1,
d1 = {"\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\b\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u0016\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u00062\u0006\u0010\u0007\u001a\u00020\u0006¨\u0006\b"},
d2 = {"Lcom/example/mylibrary/InternalClass;", "", "()V", "doSomething", "", "firstArgument", "", "secondArgument", "mylibrary_release"}
)
public final class a {
...
}
So my question: is it possible to get rid of those annotations, am I the only one facing this problem, or have I missed something?
Finally, I found a way to delete Kotlin metadata annotations.
In order to hide Kotlin metadata annotations, you need to enable R8 full mode.
Here is the information about my environment.
Environment
OS: macOS 10.15.1
Android Studio: 3.5.1
Gradle: 5.4.1
Android Gradle Tool: 3.5.2
What you have to do is just add properties to gradle.properties like below
gradle.properties
android.enableR8.fullMode=true
And here is my Proguard Rules
proguard-rules.pro
-dontwarn kotlin.**
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
}
FYI, R8 full mode is still testing now, so sometimes it doesn't work well. However, for me, it works perfectly for now.
There is some plugin dedicated for this kind of this request : https://github.com/oliver-jonas/unmeta
This plugin allows removing all Kotlin #Metadata / #DebugMetadata annotations from generated class files. This is safe to do as long as:
you do not intend to use the resulting binaries as a Kotlin library (#Metadata annotations are used to determine Kotlin function definitions),
you are not using Kotlin Reflection (certain reflection functionality depends on the presence of the #Metadata annotations).
Must be careful because when removing the metadata kotlin may your application or your library will not work.

Proguard and Scala default arguments

I have an Android Scala app that uses SBT + ProGuard for building.
In a library project I have this:
package es.fcc.bibl.bd.sincr
class Columna[T] { ... }
class TablaBase {
lazy val columnas: List[Columna[_]] = ....
}
trait Soporte {
this: TablaBase =>
def fabricaSoporte(w: Writer, cols: List[Columna[_]] = columnas) {
}
in my app code, I have this:
package es.fcc.incidencias.bd
object sgiein extends TablaBase with Soporte { .... }
and when building my project, I get these cryptic errors:
Warning: es.fcc.incidencias.bd.sgiein: can't find referenced method 'void es$fcc$bibl$bd$sincr$TablaBaseSincronizada$_setter_$cols_$eq(scala.collection.immutable.List)' in program class es.fcc.incidencias.bd.sgiein$
Warning: es.fcc.incidencias.bd.sgiein: can't find referenced method 'scala.collection.immutable.List cols()' in program class es.fcc.incidencias.bd.sgiein$
Your input classes appear to be inconsistent.
You may need to recompile the code.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)
The problem is related with the default value of the argument cols.
If I remove that argument, everything builds ok.
I've tried to change the ProGuard options to these with no luck:
-keepclassmembers class es.fcc.bibl.bd.sincr.TablaBaseSincronizada* {
** *(**);
}
-keepclassmembers class es.fcc.incidencias.bd.* {
** *(**);
}
I don't understand why I'm having this problem.
I've come to the conclusion that these errors can be safely ignored.
It must be some internal error in ProGuard.
Use the -dontwarn directive in the ProGuard configuration for that purpose.

Categories

Resources