Arrow: Android Proguard - Can't find references method 'kategory.EitherT fromEither

Created on 8 Dec 2017  Â·  23Comments  Â·  Source: arrow-kt/arrow

Hi,

First of all thanks for the library, I'm trying to get the hand of it :)

For now, When I'm trying to compile with proguard I get this error.

Warning:kategory.EitherT: can't find referenced method 'kategory.EitherT fromEither(kategory.Either,kategory.Applicative)' in program class kategory.EitherT$Companion
Warning:kategory.Kleisli: can't find referenced method 'kategory.Kleisli pure(java.lang.Object,kategory.Applicative)' in program class kategory.Kleisli$Companion
Warning:kategory.Kleisli: can't find referenced method 'kategory.Kleisli ask(kategory.Applicative)' in program class kategory.Kleisli$Companion
Warning:kategory.OptionT: can't find referenced method 'kategory.OptionT pure(java.lang.Object,kategory.Applicative)' in program class kategory.OptionT$Companion
Warning:kategory.OptionT: can't find referenced method 'kategory.OptionT none(kategory.Applicative)' in program class kategory.OptionT$Companion
Warning:kategory.OptionT: can't find referenced method 'kategory.OptionT fromOption(kategory.Option,kategory.Applicative)' in program class kategory.OptionT$Companion
Warning:there were 6 unresolved references to program class members.
Warning:Exception while processing task java.io.IOException: Please correct the above warnings first.
Error:Execution failed for task ':app:transformClassesAndResourcesWithProguardForProdRelease'.
> Job failed, see logs for details

I have only used implementation 'io.kategory:kategory:0.3.11' in my app.gradle with Android Studio 3.0

Any idea how I can solve this?

Most helpful comment

@vdubedout @pakoito we actually don't care about Java interoperability AFAIK, at least is not worth from my point of view. So removing all of them should be fine.

All 23 comments

Hello! Have you made sure to keep all companion objects for all classes in kategory?

@pakoito what those methods also seem to share in common is inline reified. A few of them are annotated with @JVMStatic

@pakoito Hey thanks for the reply, What do you mean by keeping the companion objects?

According to https://jebware.com/blog/?p=418 you'd need to add a rule to -keep class kategory.** { *; }. That should fix it. We can get more granular at a later time.

I think this is related to the conversation we had regarding Proguard and us providing a set of basic proguard rules recommendations for users. Perhaps we should add these to the docs if this is going to turn up to be a common issue on Android

Unfortunately it doesn't solves it. Same errors.

@raulraja We need some real world usage to understand the pitfalls, yes.

@vdubedout Try adding this snippet on top of keep and see if at least some of the errors disappear:

-keepclassmembers class ** {
   public static *** pure(...);
}
Warning:kategory.EitherT: can't find referenced method 'kategory.EitherT fromEither(kategory.Either,kategory.Applicative)' in program class kategory.EitherT$Companion
Warning:kategory.Kleisli: can't find referenced method 'kategory.Kleisli pure(java.lang.Object,kategory.Applicative)' in program class kategory.Kleisli$Companion
Warning:kategory.Kleisli: can't find referenced method 'kategory.Kleisli ask(kategory.Applicative)' in program class kategory.Kleisli$Companion
Warning:kategory.OptionT: can't find referenced method 'kategory.OptionT pure(java.lang.Object,kategory.Applicative)' in program class kategory.OptionT$Companion
Warning:kategory.OptionT: can't find referenced method 'kategory.OptionT none(kategory.Applicative)' in program class kategory.OptionT$Companion
Warning:kategory.OptionT: can't find referenced method 'kategory.OptionT fromOption(kategory.Option,kategory.Applicative)' in program class kategory.OptionT$Companion
Warning:there were 6 unresolved references to program class members.
Warning:Exception while processing task java.io.IOException: Please correct the above warnings first.
Error:Execution failed for task ':app:transformClassesAndResourcesWithProguardForDevRelease'.
> Job failed, see logs for details

Same problem (invalidated cache and restarted Android Studio 3.0 just before)

Okay, I'll need to repro it myself to continue investigating it. Do you have a minimally reproducible example?

* Exception is:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:transformClassesAndResourcesWithProguardForDevRelease'.
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:100)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:70)
    at org.gradle.api.internal.tasks.execution.SkipCachedTaskExecuter.execute(SkipCachedTaskExecuter.java:106)
    at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:63)
    at org.gradle.api.internal.tasks.execution.ResolveTaskOutputCachingStateExecuter.execute(ResolveTaskOutputCachingStateExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ResolveBuildCacheKeyExecuter.execute(ResolveBuildCacheKeyExecuter.java:60)
    at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
    at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
    at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
    at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
    at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
    at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.run(DefaultTaskGraphExecuter.java:248)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:197)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:107)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:241)
    at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:230)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.processTask(DefaultTaskPlanExecutor.java:124)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.access$200(DefaultTaskPlanExecutor.java:80)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:105)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker$1.execute(DefaultTaskPlanExecutor.java:99)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.execute(DefaultTaskExecutionPlan.java:625)
    at org.gradle.execution.taskgraph.DefaultTaskExecutionPlan.executeWithTask(DefaultTaskExecutionPlan.java:580)
    at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor$TaskExecutorWorker.run(DefaultTaskPlanExecutor.java:99)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
Caused by: java.lang.RuntimeException: Job failed, see logs for details
    at com.android.build.gradle.internal.transforms.ProGuardTransform.transform(ProGuardTransform.java:196)
    at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:222)
    at com.android.build.gradle.internal.pipeline.TransformTask$2.call(TransformTask.java:218)
    at com.android.builder.profile.ThreadRecorder.record(ThreadRecorder.java:102)
    at com.android.build.gradle.internal.pipeline.TransformTask.transform(TransformTask.java:213)
    at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$IncrementalTaskAction.doExecute(DefaultTaskClassInfoStore.java:173)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
    at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:121)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$1.run(ExecuteActionsTaskExecuter.java:122)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:336)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:328)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:197)
    at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:107)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:111)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:92)
    ... 29 more
Caused by: java.io.IOException: Please correct the above warnings first.
    at proguard.Initializer.execute(Initializer.java:473)
    at proguard.ProGuard.initialize(ProGuard.java:233)
    at proguard.ProGuard.execute(ProGuard.java:98)
    at com.android.build.gradle.internal.transforms.BaseProguardAction.runProguard(BaseProguardAction.java:61)
    at com.android.build.gradle.internal.transforms.ProGuardTransform.doMinification(ProGuardTransform.java:253)
    at com.android.build.gradle.internal.transforms.ProGuardTransform.access$000(ProGuardTransform.java:63)
    at com.android.build.gradle.internal.transforms.ProGuardTransform$1.run(ProGuardTransform.java:173)
    at com.android.builder.tasks.Job.runTask(Job.java:47)
    at com.android.build.gradle.tasks.SimpleWorkQueue$EmptyThreadContext.runTask(SimpleWorkQueue.java:41)
    at com.android.builder.tasks.WorkQueue.run(WorkQueue.java:259)

No mini repro example. I will create one but it will take some time.

https://github.com/vdubedout/crash-kategory-proguard

I can reproduce with this basic project. You have to build in release (where proguard is activated)

(updated it for a relative path to the junk.keystore)

As @raulraja mentioned it, all of those methods have this in common

  • @higherkind main class
  • @JvmStatic java compatibility
  • inline fun <reified>
@higherkind data class EitherT<F, A, B>(val value: HK<F, Either<A, B>>) : EitherTKind<F, A, B> {
    companion object {
        //[...]
        @JvmStatic inline fun <reified F, A, B> fromEither(value: Either<A, B>, MF: Applicative<F> = monad<F>()): EitherT<F, A, B> = MF.pure(value))
}}
@higherkind
class Kleisli<F, D, A>(val run: KleisliFun<F, D, A>) : KleisliKind<F, D, A> {
   companion object {
        @JvmStatic inline fun <reified F, D, A> pure(x: A, AF: Applicative<F> = applicative<F>()): Kleisli<F, D, A> = Kleisli({ _ -> AF.pure(x) })

        @JvmStatic inline fun <reified F, D> ask(AF: Applicative<F> = applicative<F>()): Kleisli<F, D, D> = Kleisli({ AF.pure(it) })



md5-85ca00bacf0bc0007386bc995eb3ea68



@higherkind data class OptionT<F, A>(val value: HK<F, Option<A>>) : OptionTKind<F, A> {
    companion object {
         @JvmStatic inline fun <reified F, A> pure(a: A, AF: Applicative<F> = kategory.applicative<F>()): OptionT<F, A> = OptionT(AF.pure(Option.Some(a)))

        @JvmStatic inline fun <reified F> none(AF: Applicative<F> = kategory.applicative<F>()): OptionT<F, Nothing> = OptionT(AF.pure(Option.None))

        @JvmStatic inline fun <reified F, A> fromOption(value: Option<A>, AF: Applicative<F> = kategory.applicative<F>()): OptionT<F, A> =
                OptionT(AF.pure(value))

There's probably something in the bytecode generated that's not proguard happy. I'll make a spot for it this weekend. Thank you for investigating it :D

I'm pretty sure it's the @JVMStatic biz mixed with inline reified. We don't generate any bytecode in the @higherkind codegen step. Isn't @JVMStatic just for Java interop which we don't yet care to support?
We should get rid of those if they are not buying us anything new at the moment and do a minor release if testing with a snapshot having those compiled without the @JvmStatic makes this work https://github.com/vdubedout/crash-kategory-proguard

Hey ☺
I tried to make kategory compile yesterday to do this but wasn't able to make it compile. Is there any documentation I missed for those steps. I only use android studio so it's maybe the problem.

You have to defer compilation to Gradle. Try doing ./gradlew test from CLI.

@pakoito @raulraja removing @JvmStatic actually removes the error. And we don't need to keep any proguard specific rule (removing the -keep class kategory.** rules don't show any error either). That's a quick "fix" if you don't care about Java interop. Repro Commits Fix

I have another error on this specific repro build that I don't get on my main app build. But I didn't took time to fix it too.

Warning:kategory.GlobalInstances: can't find referenced method 'java.util.concurrent.ConcurrentHashMap$KeySetView keySet()' in library class java.util.concurrent.ConcurrentHashMap

The addition IIRC was on request by @aballano. I'm happy to revert it to non-@JvmStatic, else let's figure out the solution by looking at the generated bytecode. I didn't have time for it today.

@vdubedout @pakoito we actually don't care about Java interoperability AFAIK, at least is not worth from my point of view. So removing all of them should be fine.

@pakoito I can take care now btw, i needed some motivation to code something useful today :D

Go for it!

Awesome, thanks Guys :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AntonioMateoGomez picture AntonioMateoGomez  Â·  4Comments

raulraja picture raulraja  Â·  3Comments

lgtout picture lgtout  Â·  4Comments

pakoito picture pakoito  Â·  3Comments

pakoito picture pakoito  Â·  4Comments