inner getters generate example ejemplo data java lombok

java - getters - lombok inner class



Argumentos requeridos con un lombok @Builder (9)

Aquí hay otro enfoque:

@Builder() @Getter @ToString public class Person { private final String name; private final String surname; public static PersonBuilder builder(String name){ return new PersonBuilder().name(name); } public static void main(String[] args) { Person p = Person.builder("John Doe") .surname("Bill") .build(); } }

Si agrego @Builder a una clase. Se crea el método del constructor.

Person.builder().name("john").surname("Smith").build();

Tengo un requisito donde se requiere un campo en particular. En este caso, el campo de nombre es obligatorio pero el apellido no. Idealmente, me gustaría declararlo así.

Person.builder("john").surname("Smith").build()

No puedo entender cómo hacer esto. Intenté agregar @Builder a un constructor pero no funcionó.

@Builder public Person(String name) { this.name = name; }


Combinando la respuesta de @Pawel y el comentario de Max ...

@Builder public class Person { public static class PersonBuilder { private String name; private PersonBuilder() { } public PersonBuilder(final String name) { this.name = name; } } private static PersonBuilder builder() { return null; // or we can throw exception. } public static PersonBuilder builder(final String name) { return new PersonBuilder(clientId); } }


Esta es mi solución para el problema.

import lombok.Builder; import lombok.Data; import lombok.NonNull; @Data @Builder(builderMethodName = "privateBuilder") public class Person { @NonNull private String name; @NonNull private String surname; private int age;//optional public static Url safeBuilder() { return new Builder(); } interface Url { Surname name(String name); } interface Surname { Build surname(String surname); } interface Build { Build age(int age); Person build(); } public static class Builder implements Url, Surname, Build { PersonBuilder pb = Person.privateBuilder(); @Override public Surname name(String name) { pb.name(name); return this; } @Override public Build surname(String surname) { pb.surname(surname); return this; } @Override public Build age(int age) { pb.age(age); return this; } @Override public Person build() { return pb.build(); } } }

inspirado en esta publicación de blog:

https://blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/


La solución más simple es agregar un @lombok.NonNull a todos los valores obligatorios. El generador no podrá generar el objeto cuando no se establezcan los campos obligatorios.

Aquí hay una prueba JUnit para demostrar el comportamiento de todas las combinaciones de final y @NonNull :

import static org.junit.Assert.fail; import org.junit.Test; import lombok.Builder; import lombok.ToString; public class BuilderTests { @Test public void allGiven() { System.err.println(Foo.builder().nonFinalNull("has_value").nonFinalNonNull("has_value").finalNull("has_value") .finalNonNull("has_value").build()); } @Test public void noneGiven() { try { System.err.println(Foo.builder().build().toString()); fail(); } catch (NullPointerException e) { // expected } } @Test public void nonFinalNullOmitted() { System.err.println( Foo.builder().nonFinalNonNull("has_value").finalNull("has_value").finalNonNull("has_value").build()); } @Test public void nonFinalNonNullOmitted() { try { System.err.println( Foo.builder().nonFinalNull("has_value").finalNull("has_value").finalNonNull("has_value").build()); fail(); } catch (NullPointerException e) { // expected } } @Test public void finalNullOmitted() { System.err.println( Foo.builder().nonFinalNull("has_value").nonFinalNonNull("has_value").finalNonNull("has_value").build()); } @Test public void finalNonNullOmitted() { try { System.err.println(Foo.builder().nonFinalNull("has_value").nonFinalNonNull("has_value") .finalNull("has_value").build()); fail(); } catch (NullPointerException e) { // expected } } @Builder @ToString private static class Foo { private String nonFinalNull; @lombok.NonNull private String nonFinalNonNull; private final String finalNull; @lombok.NonNull private final String finalNonNull; } }


Llevando la answer Kevin Day un paso más allá:

@Builder @Getter @AllArgsConstructor(access = AccessLevel.PRIVATE) // If immutability is desired @ToString public class Person { @NonNull // Presumably name cannot be null since its required by the builder private final String name; private final String surname; private static PersonBuilder builder() { return new PersonBuilder(); } public static PersonBuilder builder(String name){ return builder().name(name); } }

No es lo ideal, pero proporciona tiempo de compilación y las personas que llaman de esta clase tendrán exactamente un método de generador para usar.


Puede hacerlo fácilmente con la configuración de anotaciones de Lombok

import lombok.Builder; import lombok.ToString; @Builder(builderMethodName = "hiddenBuilder") @ToString public class Person { private String name; private String surname; public static PersonBuilder builder(String name) { return hiddenBuilder().name(name); } }

Y luego úsalo así

Person p = Person.builder("Name").surname("Surname").build(); System.out.println(p);

Por supuesto, @ToString es opcional aquí.


Recomendaría contra este enfoque, ya que tendrá dificultades para aplicarlo de manera consistente en otros objetos. En su lugar, puede marcar los campos con la anotación @lombok.NonNull y Lombok generará comprobaciones nulas para usted en el constructor y los establecedores, de modo que Builder.build() fallará, si esos campos no están establecidos.

El uso del patrón de construcción le permite tener una identificación muy clara de qué campos está configurando con qué valores. Esto ya se perdió para el campo de nombre en su ejemplo, y se perderá para todos los demás campos obligatorios, si está construyendo un objeto con múltiples campos obligatorios. Considere el siguiente ejemplo, ¿puede decir qué campo es cuál con solo leer el código?

Person.builder("John", "Michael", 16, 1987) // which is name, which is surname? what is 16? .year(1982) // if this is year of birth, then what is 1987 above? .build()


Si necesita esta funcionalidad, puede personalizar la clase de generador usted mismo y aún puede agregar la Anotación @Builder .

@AllArgsConstructor(access = AccessLevel.PRIVATE) // required, see https://.com/questions/51122400/why-is-lombok-builder-not-compatible-with-this-constructor @NoArgsConstructor(access = AccessLevel.PRIVATE) @Builder @Getter public class User { private String id; private String name; private int age; public static UserBuilder builder(final String id) { return new UserBuilder().id(id); } }


Tome User clase de User como ejemplo, se requiere el campo id :

import lombok.Builder; import lombok.ToString; @Builder public class Person { private String name; private String surname; public static PersonBuilder builder(String name) { return new PersonBuilder().name(name); } }

Solo puede inicializar una instancia de User por constructor como User user = User.builder("id-123").name("Tom").build; . Con el constructor privado sin argumentos, no puede User user = new User(); o User user = new User("id-123"); por lo que siempre debe pasar la id parámetro requerido. Tenga en cuenta que la instancia inicializada es inmutable.