简体   繁体   中英

Using Jackson to deserialize with Lombok builder

The Question

Lombok 's @builder annotation creates a builder-class for a class. To support deserialization of json items (using Jackson's ObjectMapper ), I've added the following annotations:

@Builder
@JsonDeserialize(builder = Item.ItemBuilder.class)
@JsonPOJOBuilder(withPrefix="")
public class Item {
    @Getter
    String partitionvalue;
}

This is based on the @Jacksonized documentation . On the usage of the deserializer, upon a json file which is stored in AWS S3 bucket and its content is simply: {"partitionvalue": "test"} , my code is:

AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
            .withCredentials(new DefaultAWSCredentialsProviderChain())
            .withRegion(region)
            .build();
S3Object s3Object = s3Client.getObject(new GetObjectRequest(bucket, key));
Item item = objectMapper.readValue(s3Object.getObjectContent(), Item.class);

However when running on a json file that Jackson fails with the message:

Unrecognized field "partitionvalue" (class com.example.Test$TestBuilder),
 not marked as ignorable (0 known properties: ])
 at [Source: com.amazonaws.services.s3.model.S3ObjectInputStream@2ca47471; line: 1, column: 21] (through reference chain: com.example.TestBuilder["partitionvalue"])

Extra Details

  • Using @ Jacksonized annotation directly didn't work as well, and since it is lombok-experimental I used the annotations I needed to use with builder directly.

  • I verified that Lombok will do what I expect of a builder class by using "delombok" option in the Lombok IntelliJ plugin:

public class Item {
    String partitionvalue;
    Item(String partitionvalue) {
        this.partitionvalue = partitionvalue;
    }
    public static ItemBuilder builder() {
        return new ItemBuilder();
    }
    public String getPartitionvalue() {
        return this.partitionvalue;
    }
    public static class ItemBuilder {
        private String partitionvalue;
        ItemBuilder() { }
        public Item.ItemBuilder partitionvalue(String partitionvalue) {
            this.partitionvalue = partitionvalue;
            return this;
        }
        public Item build() {
            return new Item(partitionvalue);
        }
        public String toString() {
            return "Item.ItemBuilder(partitionvalue=" + this.partitionvalue + ")";
        }
    }
}
  • Without the @Builder annotation (and with adding @NoArgsConstructor + @AllArgsConstructor + @Setter ) it worked fine, so the problem isn't with the file from the S3 bucket or the way it is parsed.

@JsonPOJOBuilder has to be put on the builder class, not the class itself. Without @Jacksonized , you have to customize the generated builder class as follows:

@Builder
@JsonDeserialize(builder = Item.ItemBuilder.class)
public class Item {
    @Getter
    String partitionvalue;

    @JsonPOJOBuilder(withPrefix="")
    public static class ItemBuilder {}
}

Using lombok-1.18.16 (and.18) with the @Jacksonized annotation works for me. Without that annotation, I get the same error as you do.

@Builder
@Jacksonized
public class JsonizerItem {

    @Getter private String partitionvalue;

}

@Test
void test() throws JsonProcessingException {
    JsonizerItem item = new ObjectMapper().readValue("{ \"partitionvalue\" : \"test\"}", JsonizerItem.class);
    assertEquals("test", item.getPartitionvalue());
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM