Case
Gerrit often sends a lot of emails, especially if you take part in many projects. For a while we felt that sometimes it’s hard to notice the most important ones, Read more
Gerrit often sends a lot of emails, especially if you take part in many projects. For a while we felt that sometimes it’s hard to notice the most important ones, Read more
AllArgsConstructor
annotation it will cause many problems.
AllArgsConstructor
:
@Data @AllArgsConstructor public class Person { private final String firstName; private final String lastName; private Integer age; }Now we can use generated constructor in spock test:
def 'use generated allArgsConstructor'() { when: Person p = new Person('John', 'Smith', 30) then: with(p) { firstName == 'John' lastName == 'Smith' age == 30 } }And the test is green. Let's add new optional field to our Person class -
email
:
@Data @AllArgsConstructor public class Person { private final String firstName; private final String lastName; private Integer age; private String email; }Adding optional field is considered compatible change. But our test fails...
groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.github.alien11689.allargsconstructor.Person(java.lang.String, java.lang.String, java.lang.Integer)
AllArgsConstructor
you have to ensure compatibility by adding previous version of constructor on your own:
@Data @AllArgsConstructor public class Person { private final String firstName; private final String lastName; private Integer age; private String email; public Person(String firstName, String lastName, Integer age) { this(firstName, lastName, age, null); } }And now our test again passes.
lombok.Data
is enoughData
annotation, then constructor, with only mandatory (final
) fields, will be generated. It is because Data
implies RequiredArgsConstructor
:
@Data public class Person { private final String firstName; private final String lastName; private Integer age; }
class PersonTest extends Specification { def 'use generated requiredFieldConstructor'() { when: Person p = new Person('John', 'Smith') p.age = 30 then: with(p) { firstName == 'John' lastName == 'Smith' age == 30 } } }After adding new field
email
test still passes.
Builder
annotationBuilder
generates for us PersonBuilder
class which helps us create new Person
:
@Data @Builder public class Person { private final String firstName; private final String lastName; private Integer age; }
class PersonTest extends Specification { def 'use builder'() { when: Person p = Person.builder() .firstName('John') .lastName('Smith') .age(30).build() then: with(p) { firstName == 'John' lastName == 'Smith' age == 30 } } }After adding email field test still passes.
AllArgsConstructor
you have to be sure what are you doing and know issues related to its compatibility. In my opinion the best option is not to use this annotation at all and instead stay with Data
or Builder
annotation.
Sources are available here.