2015-04-20 3 views
35

У меня есть класскак позвонить супер конструктор в Ломбок

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

У меня есть еще один класс B

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

Ломбок бросает ошибку о том, что не могу найти) конструктор (, явно назвать это то, что я хочу Ломбок, чтобы сделать это, чтобы дать аннотацию к классу Ъ, что он генерирует следующий код:

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

ли мы, есть аннотация для этого в Ломбоке?

ответ

51

Это невозможно в Ломбоке. Хотя это была бы очень хорошая функция, для этого требуется разрешение, чтобы найти конструкторы суперкласса. Суперкласс известен только по имени в момент вызова Lombok. Использование операторов import и classpath для поиска фактического класса не является тривиальным. И во время компиляции вы не можете просто использовать отражение, чтобы получить список конструкторов.

Это не совсем невозможно, но результаты с использованием разрешения в val и @ExtensionMethod научили нас, что это трудно и подвержено ошибкам.

Раскрытие информации: Я являюсь разработчиком Lombok.

+0

@ roel-spilker Мы понимаем сложности, стоящие за ним.Но может ли Lombok предоставить метод 'inConstructor' для аннотаций конструктора, где мы можем указать, какой конструктор' super' должен внести Lombok в сгенерированный конструктор? –

+0

afterConstructor было бы неплохо также выполнить некоторую автоматическую инициализацию – Pawel

+0

@ Manu/@ Pawel: см. Запрос улучшения lombok: https://github.com/peichhorn/lombok-pg/issues/78 (в настоящее время открыт) –

8

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

official documentation объясняет это, но явно не указывает, что вы можете облегчить его таким образом.

Я также нашел, что это хорошо работает с Spring Data JPA.

+0

Можете ли вы привести пример того, как это используется с Spring Data JPA? –

+7

Это не отвечает на вопрос. Вместо этого он выполняет свою работу вручную, в то время как вопрос заключается в ее создании. В то же время, это делает все более запутанным, перетаскивая @Builder, который не имеет никакого отношения к вопросу. – Jasper

+0

На самом деле это очень полезно для тех, кто просто хочет создать структуру наследования, а затем использовать построитель. Это 99%, потому что я использую #lombok в любом случае. Иногда нам просто нужно делать вещи для ручной работы, чтобы они работали так, как мы этого хотим. Так спасибо @ jj-zabkar –

3

Lombok не поддерживает то, что также указано, сделав любой @Value аннотированный класс final (как вы знаете, используя @NonFinal).

Единственное обходное решение, которое я нашел, - объявить все участники final самостоятельно и вместо этого использовать аннотацию . Эти подклассы должны быть прокомментированы @EqualsAndHashCode и нужен явно все 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; 
    } 
} 

Особенно конструкторы подклассов делают извините, решение немного неопрятное для суперклассов со многими членами.

+0

Не могли бы вы объяснить немного больше, почему «подклассы должны быть аннотированы« @ EqualsAndHashCode »? Разве это аннотация не включена в '@ Data'? Thx :) –

+0

@GerardB '@ Data' также создает equals() и hashCode(), но не заботится о каком-либо наследовании. Чтобы убедиться, что superclass equals() и hashCode() используются, вам нужно явное поколение с помощью callSuper –

1

для суперкласса с большим количеством участников, я хотел бы предложить вам использовать @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; 
    } 
} 
+0

Это интересный подход, как он! –

0

Если ребенок класс имеет больше членов, чем родители, это может быть сделано не очень чистым, но короткий путь:

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