3

Using json to save and load data requires a constructor for json to load the object, and I'm having trouble getting lombok annotations to work with this. What should I do?

This is what my class looked like before and after attempting to use an annotation to construct my item:

@Data
public class Item { //before

    private int id;

    private int amount;

    public Item(@JsonProperty("id") int id, @JsonProperty("amount") int amount) {
        this.id = id;
        this.amount = amount;
    }

}
@Data
@AllArgsConstructor 
@NoArgsConstructor //I don't want this here as it could cause complications in other places.  But json requires I have this...
public class Item { //after

    private int id;

    private int amount;

}

I don't want to use the NoArgsConstructor annotation by lombok as I don't want a no args constructor for this class. I realise that I could do this:

private Item() {
}

But was hoping there is a better way...

Jack Smith
  • 43
  • 1
  • 7

3 Answers3

4

Since lombok 1.18.4, you can configure what annotations are copied to the constructor parameters. Insert this into your lombok.config:

lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty

Then just add @JsonProperty to your fields:

@Data
@AllArgsConstructor 
public class Item {
    @JsonProperty("id")
    private int id;

    @JsonProperty("amount")
    private int amount;
}

Although the annotation parameters may seem unnecessary, they are in fact required, because at runtime the names of the constructor parameters are not available.

Jan Rieke
  • 7,027
  • 2
  • 20
  • 30
2

try adding this to your lombok config file:

lombok.anyConstructor.addConstructorProperties=true
config.stopBubbling = true
Taavi Kivimaa
  • 242
  • 1
  • 7
  • 1
    Is there no better way than this? Is there no way to annotate the constructor arguments with @JsonProprty as done in the first example of code by adding them to the AllArgsConstructor in example 2? I.e @AllArgsConstructor(argumentsAnnotation = @JsonProperty) – Jack Smith Mar 24 '19 at 08:43
0

So what you're saying is that Jackson requires no-args constructor for deserialization, and you don't want to add no-args constructors to your classes because that doesn't play well with your model.

Lombok is completely irrelevant here - it makes zero difference whether no-args constructor would be written manually or generated by Lombok, it'll still be just a no-args constructor.

Your real question is - can I make Jackson work without no-argument constructors on target classes. There are multiple answers to that already, you have almost done it. Here's what has to be done:

  1. Add @JsonCreator annotation to your constructor
  2. Add @JsonProperty("propName") to constructor parameters

You did the #2 but not #1. Add that and this should fix your problem.

mvmn
  • 3,717
  • 27
  • 30
  • And how to make something like `@Data` (Lombok) generate `@JsonCreator` onto its required-args constructor? – Voronin Sep 03 '21 at 13:02
  • 1
    Can't do it with Lombok unfortunately - if you want custom annotations you have to add the constructor with these annotations manually. – mvmn Sep 05 '21 at 07:22
  • I actually found out, that there is somewhat of a way - see https://projectlombok.org/features/experimental/onX. One can write something like this `@AllArgsConstructor(onConstructor=@__(@Inject))`, which would supposedly annotate the all-args constructor with a `@Inject` annotation (this is just an example). It's ugly, but I believe this is what I ended up using: `@Data @RequiredArgsConstructor (onConstructor_ = {@ConstructorProperties ( {"property1", "property2"})})`, annotated at the actual class. Perhaps at this point writing the constructor manually might be a better idea, though. – Voronin Sep 15 '21 at 22:54