使用Lombok @SuperBuilder和json注解的示例

19

能否有人提供一个使用 lombok @SuperBuilder 实验性注解的可运行示例?

我无法让它运行,并且没有可用于文档的代码示例。

目前我的代码看起来像这样:

超类:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
  @JsonSubTypes.Type(value = SubA.class),
  @JsonSubTypes.Type(value = AnotherSub.class)
})
@Getter
@Accessors(fluent = true, chain = true)
@SuperBuilder
public abstract class AbstractA {

    @JsonProperty
    protected final String superProperty;
}

并且子类:

@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@SuperBuilder
@JsonDeserialize(builder = SubA.SubABuilder.class) // class not found?
@JsonTypeName("SubA")
public class SubA extends AbstractA {

    @JsonProperty
    private final String fieldA;
}
感谢。
2个回答

23

更新于2018-11-10:发布Lombok 1.18.4版

更新于2020-10-18:发布Lombok 1.18.16版

Lombok 1.18.16 包含新的 @Jacksonized 注解。你只需要简单地编写如下代码:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
  @JsonSubTypes.Type(value = SubA.class),
  @JsonSubTypes.Type(value = AnotherSub.class)
})
@Jacksonized
@SuperBuilder
// more annotations...
public abstract class AbstractA {

    @JsonProperty
    protected final String superProperty;
}

@Jacksonized
@SuperBuilder
@JsonTypeName("SubA")
// more annotations...
public class SubA extends AbstractA {

    @JsonProperty
    private final String fieldA;
}

这将自动插入所有必要的Jackson注释,并对生成器进行一些调整。不再需要自定义。

对于早期的Lombok版本(1.18.4至1.18.12),请按照以下方式操作:

要使Lombok的@Builder@SuperBuilder与Jackson一起使用,您必须手动添加构建器类头,并在其上放置@JsonPOJOBuilder(withPrefix="")。然后,Lombok将仅生成剩余的构建器类。这是必要的,因为Jackson的默认设置是构建器的setter方法具有“with”作为前缀,但是Lombok的构建器没有任何前缀(而且Lombok在这方面可能永远不会配置)。

@SuperBuilder在Lombok 1.18.2中引入时,它是不可定制的(即,您无法手动添加构建器类头)。因此,使用@SuperBuilder与Jackson不容易。

这在Lombok 1.18.4中得到了改变(请参见此拉取请求):@SuperBuilder现在可以在某种程度上进行定制,这允许我们添加注释。请注意,由@SuperBuilder生成的代码非常复杂,并且具有大量的泛型。为了避免意外破坏代码,您应该查看delombok输出并从那里复制/粘贴类头。在这里,您需要添加构建器实现类头并在其上放置注释:

@JsonPOJOBuilder(withPrefix="")
static final class SubABuilderImpl extends SubABuilder<SubA, SubABuilderImpl> {
}
请注意,您必须将SubABuilderImpl的可见性至少扩大到包私有。 @JsonDeserialize注释还必须引用生成器实现类,而不是抽象生成器。
@JsonDeserialize(builder = SubA.SubABuilderImpl.class)

因此,您的意思是目前无法使用@SuperBuilder吗? - Sebastian Thees
1
它是可用的,只是不能与Jackson进行反序列化。 - Jan Rieke
1
Lombok 1.18.4已发布,现在允许自定义@SuperBuilder。我会更新我的答案以提供可行的解决方案。 - Jan Rieke
这个解决方案对我很有效。唯一的小烦恼是Eclipse报告了一些语法错误:此行有多个标记 - 实现com.company.SubA.SubABuilder<com.company.SubA,com.company.SubA.SubABuilderImpl>.self - The method $fillValuesFrom(C) is undefined for the type SubA.SubABuilder<C,B> - 类型SubA.SubABuilderBuilder<C,B>的$fillValuesFrom(C)方法必须覆盖或实现一个超类型方法 - 实现com.company.SubA.SubABuilder<C,B>.self如果有人有解决这些问题的建议,我很乐意听取。 - pconrey
首先确保Eclipse中安装的Lombok版本与Maven/Gradle中的版本匹配。您看到的消息似乎是因为层次结构中的所有类都没有设置toBuilder=true - Jan Rieke
没错,就是这个问题。我在基类上没有设置 toBuilder=true - pconrey

5

在Eclipse中可以使用的解决方案,请注意,Lombok IntelliJ集成不支持所有功能,因此代码可以在Eclipse和javac中编译,但IntelliJ认为它是有问题的,但实际上可以正常执行。

public static ObjectMapper createObjectMapper() {

    final ObjectMapper mapper = new ObjectMapper();
    mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {

        @Override
        public JsonPOJOBuilder.Value findPOJOBuilderConfig(final AnnotatedClass ac) {
            if (ac.hasAnnotation(JsonPOJOBuilder.class)) {
                return super.findPOJOBuilderConfig(ac);
            }
            return new JsonPOJOBuilder.Value("build", "");
        }
    });

    return mapper;
}

public static void main(final String[] args) throws Exception {
    final ObjectMapper objectMapper = createObjectMapper();

    final String serializedForm = objectMapper.writeValueAsString(SubA.builder().build());
    System.out.println(serializedForm);
    final SubA anA = objectMapper.readValue(serializedForm, SubA.class);
    System.out.println(anA);
}


@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@SuperBuilder
@JsonDeserialize(builder = SubA.SubABuilderImpl.class)
@JsonTypeName("SubA")
public static class SubA extends AbstractA {

    @JsonProperty
    private final String fieldA;
}


@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = SubA.class)
})
@Getter
@Accessors(fluent = true, chain = true)
@SuperBuilder
public static abstract class AbstractA {

    @JsonProperty
    protected final String superProperty;
}

我认为你是对的,IntelliJ插件在生成带注释的代码方面存在问题。 使用JsonPOJOBuilder的解决方案很有趣。 总之,现在我会采用不同的方法而不是SuperBuilder。非常感谢。 - Sebastian Thees

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接