簡體   English   中英

如何在 Lombok 中調用超級構造函數

[英]how to Call super constructor in Lombok

我有一堂課

@Value
@NonFinal
public class A {
    int x;
    int y;
}

我還有一個B班

@Value
public class B extends A {
    int z;
}

lombok 拋出錯誤,說它找不到 A() 構造函數,顯式調用它我想讓 lombok 做的是給 b 類注釋,以便它生成以下代碼:

public class B extends A {
    int z;
    public B( int x, int y, int z) {
        super( x , y );
        this.z = z;
    }
}

我們在龍目島有注釋可以做到這一點嗎?

這在龍目島是不可能的。 盡管這將是一個非常好的功能,但它需要解析才能找到超類的構造函數。 只有在調用 Lombok 時才知道超類的名稱。 使用導入語句和類路徑來查找實際類並非易事。 在編譯期間,您不能僅使用反射來獲取構造函數列表。

這並非完全不可能,但在val@ExtensionMethod使用分辨率的結果告訴我們,這很難且容易出錯。

披露:我是龍目島的開發人員。

Lombok Issue #78引用此頁面https://www.donneo.de/2015/09/16/lomboks-builder-annotation-and-inheritance/並附有這個可愛的解釋:

 @AllArgsConstructor public class Parent { private String a; } public class Child extends Parent { private String b; @Builder public Child(String a, String b){ super(a); this.b = b; } }

因此,您可以像這樣使用生成的構建器:

 Child.builder().a("testA").b("testB").build();

官方文檔對此進行了解釋,但並沒有明確指出您可以通過這種方式為其提供便利。

我還發現這與 Spring Data JPA 配合得很好。

Lombok 1.18 版引入了@SuperBuilder 注釋。 我們可以使用它以更簡單的方式解決我們的問題。

您可以參考https://www.baeldung.com/lombok-builder-inheritance#lombok-builder-and-inheritance-3

因此,在您的子類中,您將需要這些注釋:

@Data
@SuperBuilder
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)

在您的父類中:

@Data
@SuperBuilder
@NoArgsConstructor

Lombok 不支持通過將任何@Value注釋類@Value final (如您所知,使用@NonFinal )來表示。

我發現的唯一解決方法是自己將所有成員聲明為 final 並改用@Data注釋。 這些子類需要由@EqualsAndHashCode注釋,並且需要一個顯式的 all args 構造函數,因為 Lombok 不知道如何使用超類中的 all args 創建一個:

@Data
public class A {
    private final int x;
    private final int y;
}

@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A {
    private final int z;

    public B(int x, int y, int z) {
        super(x, y);
        this.z = z;
    }
}

尤其是子類的構造函數,對於成員眾多的超類來說,解決方案顯得有些凌亂,抱歉。

對於具有許多成員的超類,我建議您使用 @Delegate

@Data
public class A {
    @Delegate public class AInner{
        private final int x;
        private final int y;
    }
}

@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A {
    private final int z;

    public B(A.AInner a, int z) {
        super(a);
        this.z = z;
    }
}

如果子類的成員多於父類,則可以做得不是很干凈,但方法很短:

@Data
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class User extends BaseEntity {
    private @NonNull String fullName;
    private @NonNull String email;
    ... 

    public User(Integer id, String fullName, String email, ....) {
        this(fullName, email, ....);
        this.id = id;
    }
}

@Data
@AllArgsConstructor
abstract public class BaseEntity {
   protected Integer id;

   public boolean isNew() {
      return id == null;
   }
}

作為一個選項,您可以使用com.fasterxml.jackson.databind.ObjectMapper從父類初始化子類

public class A {
    int x;
    int y;
}

public class B extends A {
    int z;
}

ObjectMapper MAPPER = new ObjectMapper(); //it's configurable
MAPPER.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
MAPPER.configure( SerializationFeature.FAIL_ON_EMPTY_BEANS, false );

//Then wherever you need to initialize child from parent:
A parent = new A(x, y);
B child = MAPPER.convertValue( parent, B.class);
child.setZ(z);

如果需要,您仍然可以在 A 和 B 上使用任何lombok注釋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM