Lombok에서 슈퍼 생성자를 호출하는 방법


118

나는 수업이있다

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

롬복에서 할 수있는 주석이 있습니까?

답변:


169

롬복에서는 불가능합니다. 정말 멋진 기능이기는하지만 슈퍼 클래스의 생성자를 찾으려면 해결해야합니다. 수퍼 클래스는 Lombok이 호출되는 순간 이름으로 만 알려져 있습니다. import 문과 클래스 경로를 사용하여 실제 클래스를 찾는 것은 간단하지 않습니다. 컴파일하는 동안 리플렉션을 사용하여 생성자 목록을 가져올 수는 없습니다.

그것은 전적으로 불가능하지만의 해상도를 사용하여 결과 val와는 @ExtensionMethod것을 우리에게 가르쳐 그것은 하드 오류가 발생하기 쉽습니다.

공개 : 저는 롬복 개발자입니다.


@ roel-spilker 우리는 그 뒤에있는 복잡성을 이해합니다. 그러나 Lombok 은 생성 된 생성자에 Lombok이 주입 inConstructor할 생성자를 지정할 수있는 생성자 주석에 대한 메서드를 제공 할 수 super있습니까?
Manu Manjunath 2016

1
일부 자동 초기화 할뿐만 아니라 afterConstructor 좋은 일 것입니다
파블

@ 마누 / @ 파블 : 람 개선 요청 참조 : github.com/peichhorn/lombok-pg/issues/78 (현재 개방)
JJ Zabkar

@Builder가 공식 릴리스이므로 다음을 참조하십시오. github.com/rzwitserloot/lombok/issues/853
Sebastian

4
여전히 가능하지 않습니까?
FearX

22

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(); 

공식 문서는 이 설명하지만, 명시 적으로이 방법을 용이하게 할 수 있음을 지적하지 않습니다.

나는 또한 이것이 SpringData JPA와 잘 작동한다는 것을 알았습니다.


SpringData JPA와 함께 사용되는 예제를 제공 할 수 있습니까?
Marc Zampetti

29
이것은 질문에 전혀 대답하지 않습니다. 대신 손으로 작업을 수행하지만 문제는 생성 방법이었습니다. 동시에 질문과 관련이없는 @Builder를 드래그하여 모든 것을 더 혼란스럽게 만듭니다.
Jasper

8
실제로 이것은 상속 구조를 만들고 빌더를 사용하려는 사람들에게 매우 유용합니다. 이것이 제가 어쨌든 #lombok을 사용하는 99 % 이유입니다. 때때로 우리는 단지 우리가 감사를 desire.So 방식으로 작동하기 위해 공예 거즈에있는 @ JJ-zabkar
Babajide 왕자

하지만; self + parent arg 생성자를 코딩하기 만하면됩니다. 빌더를 사용할 필요가 없습니다
Juh_

STS 및 eclipse에서 작동하지만 애플리케이션의 JAR 파일을 생성하면 대부분 실패 할 것입니다. 상속을 위해 모두 SuperBuilder, Builder를 사용해 보았습니다. 둘 다 실패했습니다. 조심해 !!
P Satish Patro

6

Lombok은 @Value주석이 달린 클래스 final(를 사용하여 알고 있음)를 작성하여 표시하는 것도 지원하지 않습니다 @NonFinal.

내가 찾은 유일한 해결 방법은 모든 구성원을 최종적으로 선언하고 @Data대신 주석을 사용하는 것입니다. @EqualsAndHashCodeLombok은 수퍼 클래스 중 하나 인 all args를 사용하여 생성하는 방법을 모르기 때문에 이러한 하위 클래스에 주석을 달고 명시적인 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;
    }
}

특히 서브 클래스의 생성자는 멤버가 많은 슈퍼 클래스에 대해 솔루션을 약간 복잡하게 만듭니다. 죄송합니다.


1
"서브 클래스에 @EqualsAndHashCode" 로 주석을 달아야하는 이유 "를 좀 더 설명해 주 시겠습니까? 이 주석이에 포함되어 @Data있지 않습니까? 들으 :)
제라드 보쉬

1
@GerardB @Data는 equals () 및 hashCode ()도 생성하지만 상속에 대해서는 신경 쓰지 않습니다. (반드시 슈퍼 클래스의 등호를 만들려면)와 hashCode ()를 사용, 당신은 callSuper에 명시 적 발전이 필요
아르네 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;
    }
}

이것은 흥미로운 접근 방식입니다!
아르네 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;
   }
}


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.