3

I'm using lombok to generate constructors, getters and setters for my models. When i try to use lombok to generate the constructor for my entity class, I get this error

Error:(14, 8) error: Entities and Pojos must have a usable public 
constructor. You can have an empty constructor or a constructor whose 
parameters match the fields (by name and type).
Tried the following constructors but they failed to match:
Region(int,java.lang.String,java.lang.String) -> [param:arg0 -> matched 
field:unmatched, param:arg1 -> matched field:unmatched, param:arg2 -> 
matched field:unmatched]

but writing the constructor manually works. Can anyone help me figure out what's wrong?

My entity class is shown below

@Value
@Entity
public class Region {
    @PrimaryKey
    private int regionId;
    private String name;
    private String code;
}

Room version: 1.1.0 Lombok version: 1.16.20

Edwin Nyawoli
  • 836
  • 8
  • 20

3 Answers3

1

The matching seems to fail because the constructor parameter names are not available at runtime. Since version 1.16.20 lombok does not generate @ConstructorProperties annotations any more (which would carry those names). Try adding lombok.anyConstructor.addConstructorProperties = true to your lombok.config, and lombok will generate a @ConstructorProperties annotation for your constructor. (See https://projectlombok.org/features/configuration for details on how to configure lombok.)

EDIT: The problem is the annotation processing during compilation. Both Room and lombok hook into javac as annotation processors, and they do not work nicely in combination. So at the moment, the only stable solution is to delombok first.

Jan Rieke
  • 7,027
  • 2
  • 20
  • 30
  • Adding `lombok.anyConstructor.addConstructorProperties = true` causes the build to fail with the error: cannot find symbol class ConstructorProperties. From this [link](https://stackoverflow.com/questions/27969416/allargsconstructor-from-lombok-is-not-found-by-android-studio) , it says that annotation is not available. – Edwin Nyawoli Jul 11 '18 at 09:19
  • You probably have JDK 9 or above, and this is the reason it is not generated by default any more. Could you try including the containing module `java.desktop` to your module path? (I'm not sure whether that's possible on an android build...) – Jan Rieke Jul 12 '18 at 07:51
  • I'm actually using JDK 8 – Edwin Nyawoli Jul 13 '18 at 09:10
  • It seems the annotation is generally not available on Android. What's interesting is that your manual constructor works. It seems that somehow the parameter names survive in that case (or some other mechanism is used to let Room match the parameters correctly. However, I was unable to find details on the matching process in the Room documentation. – Jan Rieke Jul 13 '18 at 13:36
  • Maybe the problem is in the build process? Is the lombok annotationProcessor called before the Room processor? – Jan Rieke Jul 13 '18 at 13:55
  • Yes the lombok annotationProcessor is called before that of room – Edwin Nyawoli Jul 13 '18 at 17:05
  • https://stackoverflow.com/questions/29193806/specifying-order-of-annotation-processors states that the order of annotation processing cannot be influenced. Even explicitly setting the order via the "-processor" argument for javac does not work. So I think to only way is to delombok your class first. – Jan Rieke Jul 16 '18 at 12:29
1

You can use the following setup:

@Entity
@Getter
@Setter
@AllArgsConstructor(onConstructor = @__({@Ignore}))
@NoArgsConstructor
public class Region {
    @PrimaryKey
    private int regionId;
    private String name;
    private String code;
}

This will make Room use the default constructor and set the value via the provided setters. Additionally you have a constructor that accepts all arguments for object instantiation, but will be ignored by Room.

Note: Object won't be immutable that way

Collo
  • 36
  • 3
  • 1
    Welcome to StackOverflow. Thank you for taking the time to explain your answer. But can you please explain what the two constructor annotations are doing specifically? Regards. – Elletlar Feb 10 '19 at 22:10
  • 2
    Thanks. `@AllArgsConstructor` will generate a constructor for all fields of the class. With the `onConstructor = @__({@Ignore})` parameter we tell lombok to add the `@Ignore` annotation to the generated constructor. This will make Room ignore this constructor. Instead `@NoArgsConstructor` simply provides a default constructor to this class as well which will be used by Room to instantiate the object. So you can actually leave `@AllArgsConstructor(onConstructor = @__({@Ignore}))` out. Its just handy if you have to instantiate these object on your own. – Collo Feb 12 '19 at 07:51
0

Please try this as below with @Data annotation.

    @Value
    @Entity
    @Data
    public class Region {
        @PrimaryKey
        private int regionId;
        private String name;
        private String code;
    }
Sunny
  • 129
  • 1
  • 3