繁体   English   中英

与 Jackson 的不可变 Lombok 注释类

[英]Immutable Lombok annotated class with Jackson

创建类的首选方法是什么

  • 不可变
  • 可以使用 Jackson 进行序列化/反序列化
  • 人类可读和低水平的样板

最好,我会喜欢这样的工作:

@Data(onConstructor = @__(@JsonCreator))

然后将所有字段设为private final 但是,这甚至无法编译(我不确定为什么)。 使用

@AllArgsConstructor(onConstructor = @__(@JsonCreator))

将编译但只产生

InvalidDefinitionException: No serializer found for class

添加构造函数属性

  • 使用以下lombok.config适当的位置创建lombok.config文件: lombok.anyConstructor.addConstructorProperties = true
  • @Value注释添加到您的类中以使其不可变

然后杰克逊的序列化和反序列化按预期工作。

这种方法:

编辑:2020-08-16

  • 注意:将@Builder@Value @Builder使用会导致此解决方案失败。 (感谢下面来自@guilherme-blanco 的评论。)但是,如果您还添加了例如@AllArgsConstructor它仍然可以按预期工作。

编辑:2021-08-19

  • 注意:当您添加或更改lombok.config文件时,除非您进行重新构建(先清理然后构建),否则不会获取更改。 我已经被这件事抓住了几次。
  • @Jacksonized注释解决方案是另一种为注释的特定类实现所需结果的方法。 但是,我个人更喜欢不需要记住对用于反序列化的每个类进行注释。 使用lombok.config消除了这种开销。

您可以使用 Lombok 的@Builder注释为您的不可变 POJO 类生成构建器。 但是让杰克逊的反序列化可以使用 Lombok 生成的构建器有点棘手。

示例:

一个不可变的 POJO 类:

@Data
@Builder(builderClassName = "PointBuilder")
@JsonDeserialize(builder = Point.PointBuilder.class)
public class Point {

    private final int x;

    private final int y;

    @JsonPOJOBuilder(withPrefix = "")
    public static class PointBuilder {
        // Lombok will add constructor, setters, build method
    }
}

POJO大纲

这是一个用于验证序列化/反序列化的 JUnit 测试:

public class PointTest extends Assert {

    private ObjectMapper objectMapper = new ObjectMapper();

    @Test
    public void testSerialize() throws IOException {
        Point point = new Point(10, 20);
        String json = objectMapper.writeValueAsString(point);
        assertEquals("{\"x\":10,\"y\":20}", json);
    }

    @Test
    public void testDeserialize() throws IOException {
        String json = "{\"x\":10,\"y\":20}";
        Point point = objectMapper.readValue(json, Point.class);
        assertEquals(new Point(10, 20), point);
    }
}

截至 2020 年 10 月 15 日( Lombok v1.18.16 ),您应该能够简单地使用@Jacksonized注释。

 @Jacksonized @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class JacksonExample { private List<Foo> foos; }

如链接文档中所述,此注释:

  • 配置 Jackson 以使用构建器进行反序列化,
  • 将特定于字段的配置从带注释的类复制到生成的构建器(例如@JsonIgnoreProperties ),以及
  • 将用于构建器方法的 Jackson 前缀(例如builder().withField(field)builder.field(field)与 Lombok 中配置的前缀对齐。

通过参考Joseph K. Strauss 的回答,我想出了以下解决方案。

对我有用的普通 lombok 注释看起来像这样。 以下注释为您提供了具有构建器的不可变类,可以由 Jackson 序列化和反序列化。

    @Data
    @Setter(AccessLevel.NONE)
    @Builder(toBuilder = true)
    @AllArgsConstructor
    @NoArgsConstructor(access = AccessLevel.PRIVATE)
    public class Clazz {
        private String field;
    } 

我更喜欢这个解决方案,因为它不需要额外的Jackson 特定注释,也不需要额外的lombok 特定文件

另一种不那么冗长的替代方案:

@Data
@Setter(AccessLevel.NONE)
public class Clazz {
    private String field;
} 

当然,您仍然可以有一些直接修改字段的私有方法,但是在@Data POJO 中甚至不太可能有任何实际代码,因此希望不会发生这种情况。

免责声明:这将产生不让常规 Java 代码创建对象的副作用(可能是有益的),因为只有一个没有修改器的默认构造函数。 为了允许正常构建,您还需要 2 个注释:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Setter(AccessLevel.NONE)
public class Clazz {
    private String field;
} 

为您的 pojo 尝试以下一组注释:

@Value
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
@AllArgsConstructor

为 Jackson 配置不可变类的最简单方法是使用@Value注释: @Value@Jacksonized

    @Jacksonized
    @Builder
    @Value
    class Foo {

        
    }

我刚刚用这种方式解决了它:

@Value
@Builder(setterPrefix = "with")
@JsonDeserialize(builder = Clazz.ClazzBuilder.class)
public class Clazz {
    private String field;
}

在这种情况下,您必须使用像withField(...)这样的构建器方法,这是 jackson 使用的默认行为。

在 pom.xml 中添加 Jackson Dataformat 依赖项后,Thomas Fritsch 的回答与 Spring Boot 完美配合。

@Data
@Builder(builderClassName = "PointBuilder")
@JsonDeserialize(builder = Point.PointBuilder.class)
public class Point {

    private final int x;

    private final int y;

    @JsonPOJOBuilder(withPrefix = "")
    public static class PointBuilder {
        // Lombok will add constructor, setters, build method
    }
}

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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