概述

在使用Project Lombok时,我们常常希望将数据相关类与像Jackson这样的JSON框架结合。特别是在现代API和数据服务中,JSON的广泛应用使得这种需求尤为明显。

在这篇快速教程中,我们将探讨如何配置Lombok的构建器类,使其与Jackson无缝集成。

依赖项

我们首先需要在pom.xml中添加Lombok库的依赖:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
</dependency>

当然,我们还需要jackson-databind的依赖:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.14.1</version>
</dependency>

一个简单的水果领域模型

让我们定义一个启用Lombok的类,包含一个id和一个name,表示一种水果:

@Data
@Builder
@Jacksonized
public class Fruit {
    private String name;
    private int id;
}

接下来,我们逐步解释POJO的关键注解:

  • 首先,我们在类上添加@Data注解,这会生成通常与简单POJO关联的模板代码,如getter和setter方法。
  • 然后,我们添加@Builder注解——这是一个有用的机制,使用构建器模式创建对象。
  • 最重要的是,我们添加@Jacksonized注解。

简而言之,@Jacksonized@Builder的附加注解。使用这个注解可以自动配置生成的构建器类以与Jackson的反序列化功能协同工作。

需要注意的是,只有当存在@Builder@SuperBuilder注解时,@Jacksonized注解才会生效。

最后,虽然@Jacksonized在Lombok v1.18.14版本中引入,但它仍然被视为一个实验性特性

4. 反序列化和序列化

现在我们的领域模型已经定义好,让我们编写一个单元测试,使用Jackson反序列化一个水果:

@Test
public void withFruitJSON_thenDeserializeSucessfully() throws IOException {
    String json = "{\"name\":\"Apple\",\"id\":101}";
        
    Fruit fruit = newObjectMapper().readValue(json, Fruit.class);
    assertEquals(new Fruit("Apple", 101), fruit);
}

ObjectMapper的简单readValue()方法就足够了。我们可以使用它将JSON水果字符串反序列化为一个Fruit Java对象。

同样地,我们可以使用writeValue()方法将Fruit对象序列化为JSON输出:

@Test
void withFruitObject_thenSerializeSucessfully() throws IOException {
    Fruit fruit = Fruit.builder()
      .id(101)
      .name("Apple")
      .build();

    String json = newObjectMapper().writeValueAsString(fruit);
    assertEquals("{\"name\":\"Apple\",\"id\":101}", json);
}

测试展示了如何使用Lombok构建器API构建Fruit,并且序列化的Java对象与预期的JSON字符串匹配。

5. 与自定义构建器协作

有时我们需要使用自定义的构建器实现,而不是Lombok为我们生成的。例如,当我们的bean属性名称与JSON字符串中的字段名称不匹配时

假设我们想要反序列化以下JSON字符串:

{
    "id": 5,
    "name": "Bob"
}

但我们的POJO属性并不匹配:

@Data
@Builder(builderClassName = "EmployeeBuilder")
@JsonDeserialize(builder = Employee.EmployeeBuilder.class)
@AllArgsConstructor
public class Employee {

    private int identity;
    private String firstName;

}

在这种情况下,我们可以使用@JsonDeserialize注解与@JsonPOJOBuilder注解一起,插入到生成的构建器类中,以覆盖Jackson的默认设置:

@JsonPOJOBuilder(buildMethodName = "createEmployee", withPrefix = "construct")
public static class EmployeeBuilder {

    private int idValue;
    private String nameValue;

    public EmployeeBuilder constructId(int id) {
        idValue = id;
        return this;
    }
            
    public EmployeeBuilder constructName(String name) {
        nameValue = name;
        return this;
    }

    public Employee createEmployee() {
        return new Employee(idValue, nameValue);
    }
}

然后我们可以像以前一样编写测试:

@Test
public void withEmployeeJSON_thenDeserializeSucessfully() throws IOException {
    String json = "{\"id\":5,\"name\":\"Bob\"}";
    Employee employee = newObjectMapper().readValue(json, Employee.class);

    assertEquals(5, employee.getIdentity());
    assertEquals("Bob", employee.getFirstName());
}

结果显示,尽管属性名称不匹配,但仍成功从JSON源创建了一个新的Employee数据对象。

6. 总结

在这篇短文中,我们了解了两种简单的方法来配置Lombok的构建器类与Jackson无缝集成。

如果没有@Jacksonized注解,我们将不得不特别定制我们的构建器类。然而,使用@Jacksonized,我们可以利用Lombok生成的构建器类。

如往常一样,本文的完整源代码可在GitHub上获取。