Рубрики
Без рубрики

Lombok Builder со значением по умолчанию

Узнайте, как создать значения свойств по умолчанию конструктора с помощью Lombok

Автор оригинала: baeldung.

1. введение

В этом кратком руководстве мы рассмотрим, как мы можем предоставить значения по умолчанию для атрибутов при использовании шаблона builder с Lombok .

Не забудьте также ознакомиться с нашим вступлением на Ломбок.

2. Зависимости

В этом уроке мы будем использовать Lombok , и для этого нам нужна только одна зависимость:


    org.projectlombok
    lombok
    1.18.10
    provided

3. POJO С Lombok Builder

Во-первых, давайте посмотрим, как Ломбок может помочь нам избавиться от шаблонного кода, необходимого для реализации шаблона builder.

Мы начнем с простого POJO:

public class Pojo {
    private String name;
    private boolean original;
}

Чтобы этот класс был полезен, нам понадобятся геттеры. Кроме того, например, если мы хотим использовать этот класс с ORM, нам, вероятно, понадобится конструктор по умолчанию.

Кроме того, нам нужен конструктор для этого класса. С Ломбоком мы можем получить все это с помощью нескольких простых аннотаций:

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Pojo {
    private String name;
    private boolean original;
}

4. Определение ожиданий

Давайте определим некоторые ожидания относительно того, чего мы хотим достичь в форме модульных тестов.

Первое и основное требование-наличие значений по умолчанию после того, как мы построим объект с помощью конструктора:

@Test
public void givenBuilderWithDefaultValue_ThanDefaultValueIsPresent() {
    Pojo build = Pojo.builder()
        .build();
    Assert.assertEquals("foo", build.getName());
    Assert.assertTrue(build.isOriginal());
}

Конечно, этот тест не проходит, так как аннотация @Builder не заполняет значения. Мы скоро это исправим.

Если мы используем ORM, он обычно полагается на конструктор по умолчанию. Таким образом, мы должны ожидать того же поведения от конструктора по умолчанию, что и от конструктора:

@Test
public void givenBuilderWithDefaultValue_NoArgsWorksAlso() {
    Pojo build = Pojo.builder()
        .build();
    Pojo pojo = new Pojo();
    Assert.assertEquals(build.getName(), pojo.getName());
    Assert.assertTrue(build.isOriginal() == pojo.isOriginal());
}

На данном этапе этот тест проходит.

Теперь давайте посмотрим, как мы можем сделать так, чтобы оба теста прошли!

5. Строитель Ломбока.Аннотация по умолчанию

Начиная с Lombok v1.16.16, мы можем использовать внутреннюю аннотацию @Builder :

// class annotations as before
public class Pojo {
    @Builder.Default
    private String name = "foo";
    @Builder.Default
    private boolean original = true;
}

Он прост и удобочитаем, но у него есть некоторые недостатки.

При этом значения по умолчанию будут присутствовать в построителе, что сделает первый тестовый случай пройденным. К сожалению, конструктор no-args не получит значения по умолчанию, что приведет к сбою второго тестового случая . Даже если конструктор no-args не сгенерирован, а явно написан.

Это побочный эффект Builder.По умолчанию аннотация присутствует с самого начала и, вероятно, будет с нами еще долгое время.

6. Инициализируйте конструктор

Мы можем попытаться выполнить оба теста, определив значения по умолчанию в минималистичной реализации конструктора:

// class annotations as before
public class Pojo {
    private String name = "foo";
    private boolean original = true;

    public static class PojoBuilder {
        private String name = "foo";
        private boolean original = true;
    }
}

Таким образом, оба теста будут пройдены.

К сожалению, цена-дублирование кода. Для POJO с десятками полей может быть ошибкой поддерживать двойную инициализацию.

Но, если мы готовы заплатить эту цену, мы должны позаботиться еще об одной вещи. Если мы переименуем наш класс с помощью рефакторинга в нашей среде IDE, статический внутренний класс не будет автоматически переименован. Тогда Ломбок не найдет его, и наш код сломается.

Чтобы устранить этот риск, мы можем украсить аннотацию строителя:

// class annotations as before
@Builder(builderClassName = "PojoBuilder")
public class Pojo {
    private String name = "foo";
    private boolean original = true;

    public static class PojoBuilder {
        private String name = "foo";
        private boolean original = true;
    }
}

7. Использование в конструкторе

@Builder также поддерживает создание экземпляра builder из экземпляра исходного класса. По умолчанию эта функция не включена. Мы можем включить его, установив параметр to Builder в аннотации builder:

// class annotations as before
@Builder(toBuilder = true)
public class Pojo {
    private String name = "foo";
    private boolean original = true;
}

С помощью этого мы можем избавиться от двойной инициализации .

Конечно, за это есть своя цена. Мы должны создать экземпляр класса, чтобы создать конструктор. Итак, мы также должны изменить наши тесты:

@Test
public void givenBuilderWithDefaultValue_ThenDefaultValueIsPresent() {
    Pojo build =  new Pojo().toBuilder()
        .build();
    Assert.assertEquals("foo", build.getName());
    Assert.assertTrue(build.isOriginal());
}

@Test
public void givenBuilderWithDefaultValue_thenNoArgsWorksAlso() {
    Pojo build = new Pojo().toBuilder()
        .build();
    Pojo pojo = new Pojo();
    Assert.assertEquals(build.getName(), pojo.getName());
    Assert.assertTrue(build.isOriginal() == pojo.isOriginal());
}

Опять же, оба теста проходят, поэтому при использовании конструктора no-args мы имеем то же значение по умолчанию, что и при использовании конструктора.

8. Заключение

Итак, мы рассмотрели несколько вариантов предоставления значений по умолчанию для Lombok builder.

Стоит обратить внимание на побочный эффект аннотации Builder . Default . Но и у других вариантов есть свои недостатки. Поэтому мы должны тщательно выбирать, исходя из текущей ситуации.

Как всегда, код доступен на GitHub .