简体   繁体   English

Lombok @Builder 与需要特定字段的 inheritance

[英]Lombok @Builder with inheritance that requires a certain field

Java 11, Spring Boot and Lombok here. Java 11, Spring 在这里启动和龙目岛。 I am trying to build up a hierarchy of objects extending Spring's ApplicationEvent class which forces me to provide a constructor:我正在尝试建立扩展 Spring 的ApplicationEvent class 的对象层次结构,这迫使我提供一个构造函数:

public ApplicationEvent(Object source) {
   ...
}

So extending ApplicationEvent I have a TrackedEvent that is an abstract base class for my other events to build off:因此,扩展ApplicationEvent我有一个TrackedEvent ,它是一个抽象基础 class ,用于构建我的其他事件:

public abstract class TrackedEvent extends ApplicationEvent {

    private String correlationId;
    private String description;
    // ... lots of fields here

}

One of the (many) events extending TrackedEvent is OperationalEvent :扩展TrackedEvent的(许多)事件之一是OperationalEvent

public class OperationalEvent extends TrackedEvent {

    private OperationType type;
    private OperationStatus status;
    // ... several more fields here

}

Other than the source: Object field, which is required by the grandparent ApplicationEvent constructor, all other TrackedEvent and OperationalEvent fields are optional.除了source: Object字段,这是祖父ApplicationEvent构造函数所必需的,所有其他TrackedEventOperationalEvent字段都是可选的。 So because there are so many fields here to populate and instantiation-time, I feel the Builder Pattern is appropriate.所以因为这里有很多字段要填充和实例化时间,我觉得构建器模式是合适的。 So I'd like to employ Lombok's @Builder annotation (and possibly other annos) to obtain an API something like so:因此,我想使用 Lombok 的@Builder注释(可能还有其他注释)来获得 API 类似这样的东西

OperationalEvent opsEvent = OperationalEvent.Builder(this)
    .description("something happened")
    .status(OperationalStatus.THE_THING)
    .build();

My thinking here is we would pass this in as a required builder constructor argument (to satisfy ApplicationEvent 's constructor for source: Object ...somehow) and then use the @Builder like normal.我的想法是我们将this作为必需的构建器构造函数参数传递(以满足ApplicationEventsource: Object ...不知何故),然后像平常一样使用@Builder

Is this possible to do in Lombok, and if so, how?在龙目岛可以做到这一点,如果可以,怎么做?

As a fallback I can just write my own builders but since I have so many subclasses it would be great to leverage Lombok if at all possible.作为后备,我可以只编写自己的构建器,但由于我有这么多子类,如果可能的话,利用 Lombok 会很棒。

Since you can't use @SuperBuilder annotation, beacause you don't have access to ApplicationEvent class, as far as I can see, the only solution is to do something like following:由于您不能使用@SuperBuilder注释,因为您无权访问ApplicationEvent class,据我所知,唯一的解决方案是执行以下操作:

Assume that you have TrackedEvent class wich looks something like this:假设您有TrackedEvent class 看起来像这样:

public class TrackedEvent extends ApplicationEvent {
    protected String correlationId;
    protected String description;

    public TrackedEvent(Object source, String correlationId, String description) {
        super(source);
        this.correlationId = correlationId;
        this.description = description;
    }

    public TrackedEvent(Object source) {
        super(source);
    }


}

And you have OperationalEvent class wich extends above class.你有OperationalEvent class 延伸到 class 之上。 Than, you can implement builder pattern in OptionalEvent class like this:然后,您可以像这样在 OptionalEvent class 中实现构建器模式:

public class OperationalEvent extends TrackedEvent {

    private String type;
    private String status;

    public OperationalEvent(Object source) {
        super(source);
    }


    @Builder(builderMethodName = "optionalEvent")
    public OperationalEvent(Object source, String correlationId, String description, String type, String status) {
        super(source, correlationId, description);
        this.type = type;
        this.status = status;
    }

    @Override
    public String toString() {
        return "OperationalEvent{" +
                "type='" + type + '\'' +
                ", status='" + status + '\'' +
                "correlationId:" + correlationId +
                '}';
    }
}

And than the following code should work as expected:并且以下代码应该按预期工作:

public static void main(String[] args) {
    ApplicationEvent applicationEvent = new ApplicationEvent(new Object()) {
        @Override
        public Object getSource() {
            return super.getSource();
        }
    };
    OperationalEvent opsEvent = OperationalEvent.optionalEvent()
            .description("something happened")
            .source(applicationEvent)
            .status("status")
            .correlationId("1")
            .build();

}

You can use @SuperBuilder together with an intermediate abstract class, as described here .您可以将@SuperBuilder与中间抽象 class 一起使用,如此所述。

The advantage over using customized @Builder s is that you only have to manually implement this single custom intermediate class once.使用自定义@Builder的优势在于您只需手动实现这个单个自定义中间 class 一次。 There is no need for customization in every subclass.不需要在每个子类中进行定制。

In this case, the intermediate class looks as follows:在这种情况下,中间 class 如下所示:

public abstract class ApplicationEventSuperBuilderEnabler extends ApplicationEvent {

    public static abstract class ApplicationEventSuperBuilderEnablerBuilder<C extends ApplicationEventSuperBuilderEnabler, B extends ApplicationEventSuperBuilderEnablerBuilder<C, B>> {
        private Object source;

        public B source(Object source) {
            this.source = source;
            return self();
        }

        protected abstract B self();

        public abstract C build();
    }

    protected ApplicationEventSuperBuilderEnabler(ApplicationEventSuperBuilderEnablerBuilder<?, ?> b) {
        super(b.source);
    }
}

Next, let all your direct subclasses extend ApplicationEventSuperBuilderEnabler (instead of ApplicationEvent ) and put a @SuperBuilder on all classes:接下来,让您的所有直接子类扩展ApplicationEventSuperBuilderEnabler (而不是ApplicationEvent )并在所有类上放置一个@SuperBuilder

@SuperBuilder
public abstract class TrackedEvent extends ApplicationEventSuperBuilderEnabler { ... }

@SuperBuilder
public class OperationalEvent extends TrackedEvent { ... }

Now you can use it like this:现在你可以像这样使用它:

OperationalEvent opsEvent = OperationalEvent.builder()
        .source(this)
        .description("something happened")
        .status(OperationalStatus.THE_THING)
        .build();

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

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