Home > Back-end >  Spring abstract class with final fields and inheritance with lombok's @SuperBuilder
Spring abstract class with final fields and inheritance with lombok's @SuperBuilder

Time:01-03

I am currently trying to remove some boilerplate code with lombok but have some trouble.

I have an abstract class AbstractParent,

@SuperBuilder(toBuilder = true)
@EqualsAndHashCode
@ToString
@Getter
@Setter
public abstract class AbstractParent {
private final field1;
private final field2;

then I have a Child Class like this

@SuperBuilder(toBuilder = true)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public abstract class Child extends AbstractParent {

And I also have some classes extending the Child class

@SuperBuilder(toBuilder = true)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Component
public abstract class ExtendedChild extends Child {
private final field1;
private final field2;

Since lombok can't use super in a constructor, I tried the @SuperBuilder Annotation instead of defining the Constructors manually but can't get the Application to start. Am I missing something completely? Is this even possible with lombok and spring?

The Error is:

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in com.fu.extendedChild required a bean of type 'com.fu.extendedChild$extendedChildBuilder' that could not be found.


Action:

Consider defining a bean of type 'com.fu.extendedChild$extendedChildBuilder' in your configuration.

CodePudding user response:

I was able to reproduce your problem with this code

@SuperBuilder(toBuilder = true)
@EqualsAndHashCode
@ToString
@Getter
@Setter
public abstract class AbstractParent {
    private final String field1;
    private final String field2;
}

@SuperBuilder(toBuilder = true)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
abstract class Child extends AbstractParent {

}

@SuperBuilder(toBuilder = true)
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Component
class ExtendedChild extends Child {
    private final String field1;
    private final String field2;
}

What the @SuperBuilder does here on class ExtendedChild is

protected ExtendedChild(ExtendedChildBuilder<?, ?> b) {
    super(b);
    this.field1 = b.field1;
    this.field2 = b.field2;
}

So it says you need an ExtendedChildBuilder instance in order to build an ExtendedChild instance. In order words, you have to have a builder in your spring context to be able to create your object.

This is not a good idea since a builder is stateful and not thread-safe. Furthermore, the builder pattern is here to be able to provide values whenever you need them before constructing your object. Using a builder as a Spring bean denies that advantage.

If this is immutability you want to achieve, then using plain old constructors with the right parameters is way better (and when done right, this is not boilerplate code, this is good design). Then, Spring injection will be a child's play.

Please do not trade complexity for the sake of writing less code :)

  • Related