mg6maciej / hrisey

Hrisey - boilerplate code suppressor tool for Android platform
MIT License
148 stars 11 forks source link

Hrisay can't generate parcelable classes with non-parcelable superclass #6

Open rizzz87 opened 9 years ago

rizzz87 commented 9 years ago

I'm trying to use @Parcelable annotation from Hrisey library for parcelable class which should (for various reasons) extend POJO class directly (It can't be parcelable itself and I don't want to use abstract classes in the middle. It has to be direct inheritance). The thing which I want to achieve is:

public class Dummy2 {

private int valueInt;
private String valueString;

public int getValueInt() {
    return valueInt;
}

public void setValueInt(final int valueInt) {
    this.valueInt = valueInt;
}

public String getValueString() {
    return valueString;
}

public void setValueString(final String valueString) {
    this.valueString = valueString;
}
}

and the second class:

import hrisey.Parcelable;

@Parcelable
public class Dummy1 extends Dummy2 implements android.os.Parcelable {

}

The problem is that when I'm trying to build (gradlew clean build) this code with gradle I've following error:

error: cannot find symbol                             
  symbol: method writeToParcel(Parcel,int)  

Additionally, I've done also build execution with --stacktrace flag and the output is (only exception):

09:25:20.478 [DEBUG] [org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphBuilder] Selecting new module version com.android.support:support-v4:23.0
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:70)
        at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:34)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.DaemonHygieneAction.execute(DaemonHygieneAction.java:39)
        at org.gradle.launcher.daemon.server.exec.DaemonCommandExecution.proceed(DaemonCommandExecution.java:119)
        at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:46)
        at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:246)
        at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
Caused by: org.gradle.api.internal.tasks.compile.CompilationFailedException: Compilation failed; see the compiler error output for details.
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:44)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:35)
        at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.delegateAndHandleErrors(NormalizingJavaCompiler.java:97)
        at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:50)
        at org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler.execute(NormalizingJavaCompiler.java:36)
        at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:34)
        at org.gradle.api.internal.tasks.compile.CleaningJavaCompilerSupport.execute(CleaningJavaCompilerSupport.java:25)
        at org.gradle.api.tasks.compile.JavaCompile.performCompilation(JavaCompile.java:158)
        at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:138)
        at org.gradle.api.tasks.compile.JavaCompile.compile(JavaCompile.java:92)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:63)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.doExecute(AnnotationProcessingTaskFactory.java:235)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:211)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.execute(AnnotationProcessingTaskFactory.java:222)
        at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:200)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
        ... 54 more

Maybe it is a limitation of this library or annotation processing but based the documentation examples it looks like such inheritance should be possible. Anyway, I don't think that it is such rarely situation to try to inherit from POJO class. I think that it will require some investigation. Thanks!

mg6maciej commented 9 years ago

This is a limitation of this library. I've made an assumption that every class parcels its own fields. If there was no such assumption, having a proper and intuitive implementation for your case would most likely be impossible to achieve. Let me give you an example how far can this go based on your code:

  1. base class doesn't implement Parcelable, so
    1. it should be ignored
    2. it should not be ignored
  2. if not ignored
    1. fields are private, so
      1. they should be made protected during compilation and used directly
      2. matching getters and setters should be found
        1. what if there are getters and setters without backing field?
        2. what if there are fields without getter and/or setter?

It's just a simple analysis of the problem and we could probably find a few more decisions to be made. There is also no single solution that would be ok for all developers.

It's unlikely you are the only person having this requirement for your code (I've heard from one more person about this), but I'd want the code to be explicit about what it does. In your case you most likely want to use getters and setters to parcel fields from base class.

rizzz87 commented 9 years ago

Thanks for the explanation! Do you have plan to investigate this issue and prepare some solution (if possible) ? Or this issue should be just closed as 'Won't fix' because of the mentioned limitations ? Thanks in advance.

mg6maciej commented 9 years ago

I don't think there is a single working solution for all use cases.

Actually someone has asked similar thing on Hrisey's Gitter a few months ago about extending abstract classes.

If you want to start discussion on how this could be solved with code generation, I'd suggest adding a few (failing) test cases. This is a very simple operation. Just adding two files with two classes: one with annotation and the other with generated code. Take a look at ParcelableInt before and after applying transformation.

And I have just found that I even added Parcelable extending non-parcelable (it's ignored tho), which might be a good template for you to state with tests what should happen.