image

Lombok — проект по добавлению дополнительной функциональности в Java c помощью изменения исходного кода перед Java компиляцией.

По сути, проект Lombok позволяет избавиться от многословности Java в большинстве случаев и перестать писать огромные простыни кода из гетеров, сеттеров, equals, hashcode и toString (да их обычно генерит IDE, но читать и менять все равно приходится программисту), в результате Java становиться почти такой же краткой как Kotlin, Scala или C#.

Что особенно радует, Lombok очень прост и легок в добавлении к вашему проекту. Если вам, как и мне, нравится принцип KISS, то советую посмотреть на Lombok.

Так же рекомендую, посмотреть на другие статьи цикла, например последную шпаргалку по Java SE8

Добавление в проекты очень простое, достаточно добавить обычные зависимости:

Подробнее...
Maven:

       <dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<version>1.16.18</version>
	</dependency>

Так же можно (но не обязательно добавить плагин для работы статических компиляторов, если нужно анализировать код после компиляции Lombok), см. тут

Gradle

plugins {
    id 'net.ltgt.apt' version '0.10'
}

dependencies {
	compileOnly 'org.projectlombok:lombok:1.16.18'
	
	apt "org.projectlombok:lombok:1.16.18"
}

Так же есть плагины для Idea, Eclipse и т.п. Если вы собираете Gradle или Maven, то собираться будет и без этих плагинов, но будут Idea/Eclipse возможно будут показывать ошибки при анализе кода.

Команды и аннотации:
Таблица
Название Описание Пример Lombok
Пример обычной Java
@NonNull обработка переменных,
которые не должны получать null
public Example(@NonNull P p) {
 super("Hello");
 this.name = p.getName();
}

public Example(@NonNull P p) {
  super("Hello");
  if (p == null) {
    throw new NullPointerException("p");
  }
  this.name = p.getName();
}

@Getter /
@Setter
легкое создание getter’ов и
setter’ов
@Getter 
@Setter 
private int age = 10;

private int age = 10;

public int getAge() {
 return age;
} 
 
public void setAge(int age) {
  this.age = age;
}

@ToString определение аннотации перед классом,
для реализации стандартного  toString метода
@ToString(exclude="f")
public class Example

public class Example {
  @Override 
  public String toString() {
    return ...;
  }

@EqualsAndHashCode легкое создание методов Equals и HashCode
@EqualsAndHashCode(
   exclude={"id1", "id2"})
public class Example {

public class Example {
  ...
  @Override 
  public boolean equals(Object o) {
     ...
  }
  
  @Override 
  public int hashCode() {
     ...
  }

@NoArgsConstructor,
@RequiredArgsConstructor,
@AllArgsConstructor
создания пустого конструктора,
конструктора включающего все final поля,
либо конструктора включающего все возможные поля
@RequiredArgsConstructor(
     staticName = "of"
)
@AllArgsConstructor(
    access = AccessLevel.PROTECTED
)
public class E<T> {

public class E<T> {
  
 private E(T description) {
     ...
 }
  
 public static <T>E<T> of(
     T description
) {
   return new E<T>(description);
 } 

@Data генерация всех служебных методов,
заменяет сразу команды @ToString, @EqualsAndHashCode,
Getter, Setter, @RequiredArgsConstructor
@Data
public class Example { 
  private final String name;
  private int age;
}

Много кода
public class Example {
  private final String name;
  private int age;
 
  public Example(
     String name
  ) {
    this.name = name;
  }
  
  public String getName() {
    return this.name;
  }
  
  void setAge(int age) {
    this.age = age;
  }
  
  public int getAge() {
    return this.age;
  }
  
  @Override
 public String toString() {
    return ...;
  }
  
  @Override 
  public boolean equals(
    Object o
  ) {
    ....
  }
  
  @Override 
  public int hashCode() {
    ...
  }


@Value создание неизменяемых классов,
аналог Data, но для неизменяемых классов
@Value
public class Example { 
  private final String name;
  private int age;
}

Много кода
public class Example {
  private final String name;
  private final int age;
 
  public Example(
    String name, int age
) {
    this.name = name;
    this.age = age;
  }
  
  public String getName() {
    return this.name;
  }
  
  public int getAge() {
    return this.age;
  }
  
  @Override
 public String toString() {
    return ...;
  }
  
  @Override 
  public boolean equals(
     Object o
  ) {
    ....
  }
  
  @Override 
  public int hashCode() {
    ...
  }


@Builder реализация паттерна bulder,
Singular – используется для объектов в
единственном экземпляре (добавления элемента
в коллекции и т.п.)  
@Builder
public class Example {
  private String name;
  private int age;
  @Singular 
  private Set<String> occupations;
}

много кода
public class Example {
  private String name;
  private int age;
  private Set<String> occupations;
  
  Example(
    String name, 
    int age, 
   Set<String> occupations
 ) {
    this.name = name;
    this.age = age;
    this.occupations = occupations;
  }
  
  public static ExampleBuilder builder() {
    return new ExampleBuilder();
  }
  
  public static class ExampleBuilder {
    private String name;
    private int age;
    private ArrayList<> occupations;
    
    ExampleBuilder() {
    }
    
    public ExampleBuilder name(
       String name
    ) {
      this.name = name;
      return this;
    }
    
    public ExampleBuilder age(
      int age
    ) {
      this.age = age;
      return this;
    }
    
    public ExampleBuilder occupation(
      String occupation
   ) {
      if (this.occupations == null) {
        this.occupations = 
          new ArrayList<String>();
      }
      
      this.occupations.add(occupation);
      return this;
    }
    
   ...
    public Example build() {
      Set<String> occupations = ...;
      return new Example(name, age, occupations);
    }
    
    @java.lang.Override
    public String toString() {
      ...
    }
  }
}


@SneakyThrows обертка проверяемых исключений
@SneakyThrows(
UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, «UTF-8»);
}
public String utf8ToString(byte[] bytes) {
    try {
      return new String(bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw Lombok.sneakyThrow(e);
    }
 }

@Synchronized простое создание synchronized блоков
private final Object readLock = new Object();
  
@Synchronized
public static void hello() {
    ...;
 }
  
 @Synchronized
 public int answerToLife() {
   ...
 }
  
 @Synchronized("readLock")
 public void foo() {
    ...
 }

Много кода
private static final Object $LOCK = new Object[0];
private final Object $lock = new Object[0];
private final Object readLock = new Object();
  
public static void hello() {
  synchronized($LOCK) {
    ...
   }
}
  
public int answerToLife() {
  synchronized($lock) {
    ...
   }
}
  
public void foo() {
   synchronized(readLock) {
      ...
   }
}


@Log добавление инницилизации логирования,
так же позволяет выбрать вид логгера: @CommonsLog,
@JBossLog, Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j
@Slf4j
public class Example {
  public static void main(String... args) {
    log.error("error");
  }

public class Example {
  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);
  
  public static void main(String... args) {
    log.error("error");
  }

Val простое создание финальной
переменной с выводом типа,
то есть то самый val о котором
спорили
val map = new HashMap<Integer, String>();
for (val entry : map.entrySet()) {
      ...
}

final HashMap<Integer, String> map = new HashMap<Integer, String>();
...
for (final Map.Entry<Integer, String> entry : map.entrySet()) {
      ...
}

@Cleanup простое определение ресурсов,
так чтобы они автоматически закрывались
после окончания работы кода.
(не так актуально при использовании
try with resources )
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
...

InputStream in = new FileInputStream(args[0]);
    try {
      OutputStream out = new FileOutputStream(args[1]);
      try {
        ...
      } finally {
        if (out != null) {
          out.close();
        }
      }
    } finally {
      if (in != null) {
        in.close();
      }
    }





Если таблица кажется плохо читаемой, просто по очереди
Название: @NonNull
Описание: обработка переменных,
которые не должны получать null
Код Lombok:
public Example(@NonNull P p) {
 super("Hello");
 this.name = p.getName();
}

Код обычной Java:
public Example(@NonNull P p) {
  super("Hello");
  if (p == null) {
    throw new NullPointerException("p");
  }
  this.name = p.getName();
}



Название: Getter /
Setter
Описание: легкое создание getter’ов и
setter’ов
Код Lombok:
@Getter 
@Setter 
private int age = 10;

Код обычной Java:
private int age = 10;

public int getAge() {
 return age;
} 
 
public void setAge(int age) {
  this.age = age;
}



Название: @ToString
Описание: определение аннотации перед классом,
для реализации стандартного  toString метода
Код Lombok:
@ToString(exclude="f")
public class Example

Код обычной Java:
public class Example {
  @Override 
  public String toString() {
    return ...;
  }



Название: @EqualsAndHashCode
Описание: легкое создание методов Equals и HashCode
Код Lombok:
@EqualsAndHashCode(
   exclude={"id1", "id2"})
public class Example {

Код обычной Java:
public class Example {
  ...
  @Override 
  public boolean equals(Object o) {
     ...
  }
  
  @Override 
  public int hashCode() {
     ...
  }



Название:
@NoArgsConstructor,
@RequiredArgsConstructor,
@AllArgsConstructor
Описание: создания пустого конструктора,
конструктора включающего все final поля,
либо конструктора включающего все возможные поля
Код Lombok:
@RequiredArgsConstructor(
     staticName = "of"
)
@AllArgsConstructor(
    access = AccessLevel.PROTECTED
)
public class E<T> {

Код обычной Java:
public class E<T> {
  
 private E(T description) {
     ...
 }
  
 public static <T>E<T> of(
     T description
) {
   return new E<T>(description);
 } 



Название: Data
Описание: генерация всех служебных методов,
заменяет сразу команды @ToString, @EqualsAndHashCode,
Getter, Setter, @RequiredArgsConstructor
Код Lombok:
@Data
public class Example { 
  private final String name;
  private int age;
}



public class Example {
  private final String name;
  private int age;
 
  public Example(
     String name
  ) {
    this.name = name;
  }
  
  public String getName() {
    return this.name;
  }
  
  void setAge(int age) {
    this.age = age;
  }
  
  public int getAge() {
    return this.age;
  }
  
  @Override
 public String toString() {
    return ...;
  }
  
  @Override 
  public boolean equals(
    Object o
  ) {
    ....
  }
  
  @Override 
  public int hashCode() {
    ...
  }




Название: Value
Описание: создание неизменяемых классов,
аналог Data, но для неизменяемых классов
Код Lombok:
@Value
public class Example { 
  private final String name;
  private int age;
}


Код обычной Java:
public class Example {
  private final String name;
  private final int age;
 
  public Example(
    String name, int age
) {
    this.name = name;
    this.age = age;
  }
  
  public String getName() {
    return this.name;
  }
  
  public int getAge() {
    return this.age;
  }
  
  @Override
 public String toString() {
    return ...;
  }
  
  @Override 
  public boolean equals(
     Object o
  ) {
    ....
  }
  
  @Override 
  public int hashCode() {
    ...
  }




Название: Builder
Описание: реализация паттерна bulder,
Singular – используется для объектов в
единственном экземпляре (добавления элемента
в коллекции и т.п.)  
Код Lombok:
@Builder
public class Example {
  private String name;
  private int age;
  @Singular 
  private Set<String> occupations;
}


Код обычной Java:
public class Example {
  private String name;
  private int age;
  private Set<String> occupations;
  
  Example(
    String name, 
    int age, 
   Set<String> occupations
 ) {
    this.name = name;
    this.age = age;
    this.occupations = occupations;
  }
  
  public static ExampleBuilder builder() {
    return new ExampleBuilder();
  }
  
  public static class ExampleBuilder {
    private String name;
    private int age;
    private ArrayList<> occupations;
    
    ExampleBuilder() {
    }
    
    public ExampleBuilder name(
       String name
    ) {
      this.name = name;
      return this;
    }
    
    public ExampleBuilder age(
      int age
    ) {
      this.age = age;
      return this;
    }
    
    public ExampleBuilder occupation(
      String occupation
   ) {
      if (this.occupations == null) {
        this.occupations = 
          new ArrayList<String>();
      }
      
      this.occupations.add(occupation);
      return this;
    }
    
   ...
    public Example build() {
      Set<String> occupations = ...;
      return new Example(name, age, occupations);
    }
    
    @java.lang.Override
    public String toString() {
      ...
    }
  }
}




Название: @SneakyThrows
Описание: обертка проверяемых исключений
Код Lombok:

@SneakyThrows(
UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, «UTF-8»);
}

Код Lombok:
public String utf8ToString(byte[] bytes) {
    try {
      return new String(bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      throw Lombok.sneakyThrow(e);
    }
 }



Название: @Synchronized
Описание: простое создание synchronized блоков
Код Lombok:
private final Object readLock = new Object();
  
@Synchronized
public static void hello() {
    ...;
 }
  
 @Synchronized
 public int answerToLife() {
   ...
 }
  
 @Synchronized("readLock")
 public void foo() {
    ...
 }


Код обычной Java:
private static final Object $LOCK = new Object[0];
private final Object $lock = new Object[0];
private final Object readLock = new Object();
  
public static void hello() {
  synchronized($LOCK) {
    ...
   }
}
  
public int answerToLife() {
  synchronized($lock) {
    ...
   }
}
  
public void foo() {
   synchronized(readLock) {
      ...
   }
}




Название: Log
Описание: добавление инницилизации логирования,
так же позволяет выбрать вид логгера: @CommonsLog,
@JBossLog, Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j
Код Lombok:
@Slf4j
public class Example {
  public static void main(String... args) {
    log.error("error");
  }

Код обычной Java:
public class Example {
  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);
  
  public static void main(String... args) {
    log.error("error");
  }



Val простое создание финальной
переменной с выводом типа,
то есть то самый val о котором
спорили
val map = new HashMap<Integer, String>();
for (val entry : map.entrySet()) {
      ...
}

final HashMap<Integer, String> map = new HashMap<Integer, String>();
...
for (final Map.Entry<Integer, String> entry : map.entrySet()) {
      ...
}



Название: @Cleanup
Описание: простое определение ресурсов,
так чтобы они автоматически закрывались
после окончания работы кода.
(не так актуально при использовании
try with resources )
Код Lombok:
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
...

Код обычной Java:
InputStream in = new FileInputStream(args[0]);
    try {
      OutputStream out = new FileOutputStream(args[1]);
      try {
        ...
      } finally {
        if (out != null) {
          out.close();
        }
      }
    } finally {
      if (in != null) {
        in.close();
      }
    }

Комментарии (33)


  1. akass
    26.12.2017 13:50
    +1

    Планируется ли обзор DI решений (Guice, Dagger, HK2)?


    1. vedenin1980 Автор
      26.12.2017 13:52

      Да, уже есть наполовину написанная статья по Guice, Dagger, Spring, с HK2 не сталкивался, посмотрю.


  1. NimElennar
    26.12.2017 17:29
    +1

    Беда начинается, когда требуется в одном проекте использовать и Lombok и AspectJ, они не очень дружат.


    1. vedenin1980 Автор
      26.12.2017 17:38

      А можете рассказать, что происходит? Я не сталкивался с такими проблемами, вроде AspectJ по идее работает уже с сгенеренными классами (или я ошибаюсь?), а сгенеренные классы Lombok не отличаются от обычных.


      1. NimElennar
        26.12.2017 21:22

        palesz.wordpress.com/2011/12/03/howto-maven-lombok-and-aspectj-together
        1. javac compiles your .java files to .class files with lombok (generating methods, etc.)
        2. aspectj regenerates your classes from the .java files without lombok
        Но, к сожалению, предложенный по ссылке вариант у меня не сработал. И не только у меня, насколько можно понять из issue того же lombok — github.com/rzwitserloot/lombok/issues/995


  1. igorperciuleac
    26.12.2017 17:29
    +2

    Никогда не понимал людей кто юзает эту либу.
    Для нового продукта можно выбрать лаконичные scala или koltin.
    А в бородатый энтерпрайз вряд ли кто то станет это внедрять.
    Нужно принимать язык таким как каким он есть.


    1. vedenin1980 Автор
      26.12.2017 17:49
      -1

      Для нового продукта можно выбрать лаконичные scala или koltin.

      Можно, но если вся команда привыкла писать на Java почему бы и нет. У scala многих пугает сложность, понятно, что можно писать как чуть лучшая Java, но если работать с чужим кодом можно ничего не понять. koltin пока не так распространен. Данная библиотека это компромис между новым языком и старым.

      А в бородатый энтерпрайз вряд ли кто то станет это внедрять.

      Кроме энтерпрайза есть просто старые проекты, которые по каким-то причинам использовали Java (скажем, микросервисы). С одной стороны переходит на новый язык сложно, с другой добавление библиотеки позволяет рефакторить старый код. Вообще, в Java энтерпрайз все больше переходит на Spring Boot и микросервисы, а это могут быть совсем не огромные проекты.

      Нужно принимать язык таким как каким он есть.

      Не согласен, так можно было вообще писать на Java 5 или Java 3. Язык вполне гибкая штука, в Java огромное количество открытых библиотек, которые тоже расширяют возможности. По такой логики их тоже не стоит использовать.


      1. igorperciuleac
        26.12.2017 18:52
        +2

        Не согласен, так можно было вообще писать на Java 5 или Java 3. Язык вполне гибкая штука, в Java огромное количество открытых библиотек, которые тоже расширяют возможности. По такой логики их тоже не стоит использовать.

        Вы передергиваете :) Речь ведь о языке в целом, а не конкретно какой-то её версии.
        Генерация кода для DI вынужденная мера, тут я согласен.
        В остальном, не западло прописать getter/setter потому что это Java, тут так принято.

        Хотите нормальную аргументацию?
        Для нормальной работы этого чудо модуля нужно ставить расширение для IntelliJ IDEA
        Все эти генерации могут усложнить/замедлить скорость сборки проекта
        Все эта магия вгонит в ступор первого же человека кто начнет разбираться в таком коде.

        Ненужно пытаться нагнать всевдо-читаемость такими плагинами.
        Если что, есть много других языков где ненужно писать getter/setter :)


        1. acmnu
          26.12.2017 20:00

          Если что, есть много других языков где ненужно писать getter/setter :)

          Эм… Много? Что-то как-то в голову даже 5 не приходит.


          1. igorperciuleac
            26.12.2017 22:08

            Ruby, Python, Swift, Scala, Kotlin


            1. acmnu
              27.12.2017 00:19

              Ай, блин, _не_нужно. Прочитал не верно


        1. AstarothAst
          27.12.2017 11:20

          Все эта магия вгонит в ступор первого же человека кто начнет разбираться в таком коде.

          Спринговый @Compontent тоже вгонит, так что ж теперь, Спрингом не пользоваться?


          1. igorperciuleac
            27.12.2017 11:34

            Аннотация @Compontent в отличии от аннотаций Lombok не дописывает код вместо вас, вот в чем разница!


            1. AstarothAst
              27.12.2017 11:43

              Для человека, который этого не знает и та и другая аннотация выглядят магически и требуют времени для постижения того, что это такое и как работает, так что с этой точки зрения разница не велика. При этом, замечу, квикдок по аннотации Data первым делом сообщает: "Generates getters for all fields", плюс дает ссылку на сайт ломбока, что сильно помогает делу.


              1. igorperciuleac
                27.12.2017 11:54

                Я не знаю как по другому еще донести до вас суть. Вы меня не хотите слышать, эта ветка зашла в тупик.


                1. AstarothAst
                  27.12.2017 11:59

                  Суть вами сказанного, собственно, ясна. Просто есть иной взгляд на вещи, вот и все.


                  1. igorperciuleac
                    27.12.2017 12:07

                    Для меня лично не приемлем тот факт что без специального плагина для IDE с этим самым Lombok невозможно нормально работать. Это главная причина того, почему я не буду использовать это в своих проектах.


                    1. AstarothAst
                      27.12.2017 13:14

                      Со Спрингом, кстати, тоже невозможно нормально работать в комьюнити эдишн версии, но многие работают, и при этом говорят, что им норм :)


              1. data
                28.12.2017 08:11

                парсер, что ты делаешь, прекрати


    1. Sultansoy
      26.12.2017 20:35
      -1

      Ну мне лично не нравится синтаксис котлина и скали, а джава с си подобным синтаксисом очень даже ничего. В принципе сгенерировать через alt insert в идее эти геттеры сеттеры тоже не сложно, но ломбок вообще шикарен.


    1. AstarothAst
      27.12.2017 11:17
      +1

      Есть объект класса, нужно вернуть его часть в виде json — я создаю отдельную обертку, которая в конструктор принимает этот объект, и берет из него все нужное, после чего объект обертки прогоняется через jackson, и на выходе получаем json. Jackson, как известно, пользуется для конвертации либо публичными полями, либо геттерами, поэтому одна единственная аннотация Data над классом-оберткой быстро и не заметно экономит мне время. Еще одна аннотация @Slf4j позволяет мне работать с логгером даже не думая о нем. В общем не очень понимаю ваше не понимание, о каком «внедрении в бородатый энтерпрайз» вообще идет речь? Это же библиотека, а не фреймворк — если удобно, то используем, если не удобно, то не используем.


      1. igorperciuleac
        27.12.2017 11:31
        +1

        Немного необычный подход с оберткой над объектом для генерации json.
        Обычно делаются статические методы в хелпер-классе, например EntityHelper.toJson(myEntity)
        В вашем случае идет совершенно ненужное создание +1 объекта обертки к каждой операции конвертации объекта в Json

        Не буду спорить что ваш подход выглядит короче, круче :)


        1. AstarothAst
          27.12.2017 11:51

          Ваш подход не подойдет в случае если нет однозначного соответствия Класс<->json. То есть в одном случае нужен json состоящий из некоторых полей класса А, в другом — из всех полей, а в третьем случае вообще должен быть композицией из A + B + C. Плюс мне нравится иметь возможность на вопрос «почему фронту приходит ЭТО вместо ЭТОГО?» пойти и подправить одну конкретную обертку гарантированно не затронув ничего по соседству. Я такие обертки вообще частенько создаю, как inner классы прямо по месту преобразования результата.


          1. igorperciuleac
            27.12.2017 12:03

            Нужно конечно видеть код, что бы подсказать альтернативный путь для решения этой задачи без дополнительных объектов-оберток.
            Возможно что ваш подход хорошо подходит именно в вашем случае. Тут я спорить не буду.


            1. AstarothAst
              27.12.2017 13:15

              А в чем проблема дополнительных оберток, кстати говоря? Формально понятно, лишняя сущность, но практически она маленькая, локальная и вопросов не вызывает. Стоит ли с ней бороться?


              1. igorperciuleac
                27.12.2017 13:27

                В вашем случае, на сколько я понял, это обертка возвращается вашим контроллером, по сути ничего, кроме эстетического момента меня не смущает.

                Если же вы проектируете api какой-либо библиотеки, которую будут использовать сторонние разработчики, то тут я бы воздержался от таких конструкций. Разработчик может вызывать такой код в различных циклах миллионы раз, зачем провоцировать GC на лишнюю работу за зря?


                1. AstarothAst
                  27.12.2017 13:39

                  Не совсем так. У меня выделена отдельная сущность «экшен», который с одной стороны может вызываться на выполнение фронтэндом, путем отправления по вебсокету специального сообщения, а с другой стороны в него интегрирован доступ к ядерным сервисам, которые обеспечивают работу самого приложения, и знать не знают ни о какой фронтовой части. То есть реализуя экшен (java код) на получение, к примеру, данных о работнике, которые на ядерном уровне распределены по нескольким компонентам, мы делам примерно так:
                  UserProfile userProfile = userService.getProfile(id);
                  EmployeeProfile employeeProfile = employeeService.getProfile(id);

                  после чего компонуем эти два профиля в одну entity, состоящую, скажем, из ФИО (взятого из userProfile) и количества рабочих часов в месяц (из employeeProfile), которую экшен и возвращает для дальнейшего превращения в json, и возврата фронтэнду. При таком подходе результирующий entity даже в виде inner класса в классе экшена смотрится довольно уместно.

                  А насчет библиотеки это да, тут согласен.


  1. 3draven
    26.12.2017 23:31

    Пользую ломбок давненько, в основном Getter/Setter/ToString/Equal…
    По моему удобно и Entity сокращаются в размерах в разы.

    Только следить за циклическими зависимостями в ManyToMany и прочих подобных штуках надо путем использования exclude ну и с Equal… осторожно, в остальном просто супер.


  1. Timmmm
    27.12.2017 11:46

    Табличный формат совершенно не удобен, вы разве не видите?


    1. vedenin1980 Автор
      27.12.2017 12:07

      Добавил альтернативный формат, спасибо


  1. DarkByte2015
    27.12.2017 13:24

    Выглядит круто, только вот один вопрос очень интересует: если физически в коде например геттеров/сеттеров нет (добавятся аннотацией), а ты их будешь юзать, не будет ли IDE их подчеркивать все время как ошибку? Она то не знает что они добавятся во время компиляции… И вообще как с ними автокомплит будет работать?


    1. vedenin1980 Автор
      27.12.2017 13:25

      Для всех IDE есть специальные плагины, при которых все работает нормально.


    1. AstarothAst
      27.12.2017 13:45

      Idea при установленном lombok-plugin все показывает корректно
      image