3

For my android app I use the parceler library and the lombok library.

These are the annotations of my class:

@Table
@ToString
@Getter
@NoArgsConstructor
@Parcel
public class MyClass {

However, during gradle build, Parceler complains that there is no default empty constructor. So does this mean it doesn't recognize the @NoArgsConstructor annotation and these two simply won't work together? Because e.g. SugarORM has no probs with it. Or am I just missing something?

cherry-wave
  • 731
  • 2
  • 6
  • 21

3 Answers3

4

This gets into how Lombok adds code to your class. Lombok uses a known trick in the Java annotation processor to add code to your class. This added code is not visible to Parceler during the annotation processor round and makes the added no-args constructor unknown to Parceler.

I'd recommend adding the no-args constructor manually, annotating the existing constructor with @ParcelConstructor (I assume you have one) or consider using the Lombok fork Hrisey that has an @Parcelable annotation.

We had an issue/question about this recently: https://github.com/johncarl81/parceler/issues/177

John Ericksen
  • 10,995
  • 4
  • 45
  • 75
  • Nice to see someone from the "parcelers" directly ;D Yeah I guessed that. I made a no args constructor myself by now. Do you recommend Hrisey? It would indeed combine the use of two libraries into one. – cherry-wave Jun 01 '16 at 07:36
  • I haven't used it myself, but it looks like it would do the trick. – John Ericksen Jun 01 '16 at 14:31
1

EDIT: Initial solution failed after I did some cleaning, also, it didn't work with Proguard. See updated solution below.

To solve this problem, I had to create my own custom annotation processor. The idea of this processor was to ensure processor order for the processors used by Lombok and Parceler.

Here are the steps I followed to resolve this problem:

Step 1

Create a new Java Module under the root project. Call it any name, for example parceler-lombok, use any class name/package of your choice.

Step 2

Add lombok and Parceler annotation classes as dependency to the new module, and set source compatibility.

//File: parceler-lombok/build.gradle
apply plugin: 'java'
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'org.projectlombok:lombok:1.16.16'
    compile 'org.parceler:parceler:1.1.9'
}

sourceCompatibility = "1.7"
targetCompatibility = "1.7"

Step 3

Create the following directory in your main source folder for the module: src/main/resources/META-INF/services

Step 4

Create a file called javax.annotation.processing.Processor inside the directory above.

Step 5

Edit the file, and add the following lines.

lombok.launch.AnnotationProcessorHider$AnnotationProcessor
lombok.launch.AnnotationProcessorHider$ClaimingProcessor
org.parceler.ParcelAnnotationProcessor

This is a declaration of all the annotation processors available in your module. The order shows that Lombok annotation processors should be loaded before parceler's

Step 6

Now that we have our "custom annotation processor", go back to your main app module, in your build.gradle file for app, do the following:

  • Remove lombok dependency (annotatorProcessor, provided or compile) directive
  • Remove the parceler annotationProcessor dependency (i.e. org.parceler:parceler), leave the API dependency as-is.
  • Now add your custom annotation processor as a dependency
  • Finally, ensure Java 1.7 compatibility

See snippets below :

//File: app/build.gradle
android {
  //...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
  //...
}

dependencies {
    // ...
    //Remove these ones
    //provided 'org.projectlombok:lombok:1.16.16'
    //annotationProcessor 'org.parceler:parceler:1.1.9'

    //leave parceler API
    compile 'org.parceler:parceler-api:1.1.9'
    provided project(':parceler-lombok')
}

Using provided ensures that the annotation processor classes are not bundled with your app.


The following articles were very helpful:

tlogbon
  • 1,212
  • 13
  • 12
  • The initial solution failed when I tried using proguard. After hours of research, I was able to solve the issue. See new solution. – tlogbon Feb 10 '18 at 11:51
0

Use @ParcelFactory on a static method building an empty object:

@Builder
public class MyClass {
    @ParcelFactory
    static MyClass fromParcel() {
        return builder().build();
    }
}

This trick can ben used with Jackson and other libraries allowing you to annotate static factory methods in addition to constructors.

Simon Guerout
  • 652
  • 6
  • 17