วิธีการโทรหา super constructor ในลอมบอก


118

ฉันมีชั้นเรียน

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

ฉันมีคลาส B อีกคน

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

ลอมบ็อกเกิดข้อผิดพลาดโดยบอกว่าไม่พบตัวสร้าง A () เรียกอย่างชัดเจนว่าสิ่งที่ฉันต้องการให้ลอมบอกทำคือให้คำอธิบายประกอบกับคลาส b เพื่อให้สร้างรหัสต่อไปนี้:

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

เรามีคำอธิบายประกอบในการทำเช่นนั้นในลอมบอกหรือไม่?

คำตอบ:


169

สิ่งนี้ไม่สามารถทำได้ในลอมบอก แม้ว่ามันจะเป็นคุณสมบัติที่ดีมาก แต่ก็ต้องใช้ความละเอียดในการค้นหาคอนสตรัคเตอร์ของซูเปอร์คลาส ซูเปอร์คลาสเป็นที่รู้จักกันในชื่อเฉพาะในขณะที่ลอมบอกถูกเรียกใช้ การใช้คำสั่ง import และ classpath เพื่อค้นหาคลาสจริงนั้นไม่สำคัญ และในระหว่างการรวบรวมคุณไม่สามารถใช้การสะท้อนเพื่อรับรายชื่อผู้สร้างได้

ไม่ใช่เรื่องที่เป็นไปไม่ได้เลย แต่ผลลัพธ์ที่ใช้ความละเอียดvalและ@ExtensionMethodได้สอนเราว่ามันยากและเกิดข้อผิดพลาดได้ง่าย

การเปิดเผยข้อมูล: ฉันเป็นผู้พัฒนา Lombok


@ roel-spilker เราเข้าใจถึงความซับซ้อนที่อยู่เบื้องหลังมัน แต่ลอมบอกสามารถจัดหาinConstructorวิธีการสำหรับคำอธิบายประกอบตัวสร้างที่เราสามารถระบุได้ว่าผู้สร้างของsuperลอมบอกจะฉีดตัวสร้างใดในตัวสร้างที่สร้างขึ้น?
Manu Manjunath

1
afterConstructor จะดีเช่นกันหากต้องการเริ่มต้นอัตโนมัติ
Pawel

@ Manu / @ Pawel: ดูคำขอการปรับปรุง lombok: github.com/peichhorn/lombok-pg/issues/78 (เปิดให้บริการในปัจจุบัน)
JJ Zabkar

เนื่องจาก @Builder อยู่ในการเผยแพร่อย่างเป็นทางการโปรดดูที่github.com/rzwitserloot/lombok/issues/853
Sebastian

4
ยังเป็นไปไม่ได้?
FearX

21

ลอมบอกฉบับที่ 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


คุณสามารถยกตัวอย่างของสิ่งนี้ที่ใช้กับ Spring Data JPA ได้หรือไม่?
Marc Zampetti

30
นี้ไม่ตอบคำถามเลย แต่มันทำงานด้วยมือในขณะที่คำถามคือวิธีสร้างมัน ในขณะเดียวกันก็ทำให้เรื่องทั้งหมดสับสนมากขึ้นโดยการลาก @Builder ซึ่งไม่มีส่วนเกี่ยวข้องกับคำถาม
Jasper

8
อันที่จริงสิ่งนี้มีประโยชน์มากสำหรับผู้ที่ต้องการสร้างโครงสร้างการสืบทอดจากนั้นใช้ตัวสร้าง นี่คือเหตุผล 99% ที่ฉันใช้ #lombok อย่างไรก็ตาม บางครั้งเราก็ต้องประดิษฐ์สิ่งของด้วยมือเพื่อให้มันทำงานได้ตามที่เราต้องการขอบคุณมาก @ jj-zabkar
Babajide Prince

แต่แล้ว; เพียงแค่เขียนโค้ดตัวสร้างอาร์กิวเมนต์ self + parent ไม่ต้องใช้ช่างก่อสร้าง
Juh_

มันจะทำงานใน STS & eclipse แต่เมื่อคุณสร้างไฟล์ JAR ของแอปพลิเคชันของคุณส่วนใหญ่อาจล้มเหลว ฉันลองทั้ง SuperBuilder, Builder เพื่อสืบทอด ทั้งคู่ล้มเหลว ระวัง !!
P Satish Patro

6

Lombok ไม่สนับสนุนสิ่งที่ระบุด้วยการสร้าง@Valueคลาสที่มีคำอธิบายประกอบfinal(ดังที่คุณทราบโดยใช้@NonFinal)

วิธีแก้ปัญหาเดียวที่ฉันพบคือการประกาศให้สมาชิกทุกคนเป็นคนสุดท้ายด้วยตัวคุณเองและใช้@Dataคำอธิบายประกอบแทน คลาสย่อยเหล่านั้นจำเป็นต้องมีคำอธิบายประกอบ@EqualsAndHashCodeและจำเป็นต้องมีตัวสร้าง args ทั้งหมดที่ชัดเจนเนื่องจาก Lombok ไม่ทราบวิธีสร้างโดยใช้ args ทั้งหมดหนึ่งใน super class:

@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;
    }
}

โดยเฉพาะอย่างยิ่งผู้สร้างของคลาสย่อยทำให้การแก้ปัญหาไม่เป็นระเบียบเล็กน้อยสำหรับซูเปอร์คลาสที่มีสมาชิกจำนวนมากขออภัย


1
คุณช่วยอธิบายเพิ่มเติมอีกเล็กน้อยได้ไหมว่าทำไม "คลาสย่อยจึงต้องมีคำอธิบายประกอบ@EqualsAndHashCode" ไม่รวมคำอธิบายประกอบนี้โดย@Data? Thx :)
Gerard Bosch

1
@GerardB @Dataยังสร้าง equals () และ hashCode () แต่ไม่สนใจการสืบทอดใด ๆ เพื่อให้แน่ใจว่าใช้ superclass เท่ากับ () และ hashCode () คุณต้องมีการสร้างที่ชัดเจนด้วย callSuper
Arne Burmeister

5

สำหรับซูเปอร์คลาสที่มีสมาชิกจำนวนมากฉันขอแนะนำให้คุณใช้ @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;
    }
}

นี่เป็นแนวทางที่น่าสนใจเช่นกัน!
Arne Burmeister

@Delegateคือ@Target({ElementType.FIELD, ElementType.METHOD}). ควรจะเป็นในสนามAInner A
boriselec

3

หากคลาสย่อยมีสมาชิกมากกว่าผู้ปกครองอาจทำได้ไม่สะอาดนัก แต่วิธีสั้น ๆ :

@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;
   }
}

3

เวอร์ชัน 1.18 ของลอมบอกเปิดตัวคำอธิบายประกอบ @SuperBuilder เราสามารถใช้สิ่งนี้เพื่อแก้ปัญหาของเราด้วยวิธีที่ง่ายกว่านี้

คุณสามารถดูhttps://www.baeldung.com/lombok-builder-inheritance#lombok-builder-and-inheritance-3

ดังนั้นในชั้นเรียนลูกของคุณคุณจะต้องมีคำอธิบายประกอบเหล่านี้:

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

ในชั้นเรียนผู้ปกครองของคุณ:

@Data
@SuperBuilder
@NoArgsConstructor

0

เป็นตัวเลือกที่คุณสามารถใช้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);

คุณยังสามารถใช้lombokคำอธิบายประกอบบน A และ B ได้หากต้องการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.