{"id":12835,"date":"2016-01-17T16:40:00","date_gmt":"2016-01-17T15:40:00","guid":{"rendered":"https:\/\/touk.pl\/blog\/?guid=cc42624f4761c1d78826ad96bd2f61b2"},"modified":"2023-04-27T11:31:10","modified_gmt":"2023-04-27T09:31:10","slug":"do-not-use-allargsconstructor-in-your-public-api","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2016\/01\/17\/do-not-use-allargsconstructor-in-your-public-api\/","title":{"rendered":"Do not use AllArgsConstructor in your public API"},"content":{"rendered":"<h2 id=\"introduction\">Introduction<\/h2>\n<p>Do you think about compatibility of your public API when you modify classes from it? It is especially easy to miss out that something incompatibly changed when you are using <a href=\"https:\/\/projectlombok.org\/\">Lombok<\/a>. If you use <a href=\"https:\/\/projectlombok.org\/api\/lombok\/AllArgsConstructor.html\"><code>AllArgsConstructor<\/code><\/a> annotation it will cause many problems.<\/p>\n<h2 id=\"what-is-the-problem\">What is the problem?<\/h2>\n<p>Let&#8217;s define simple class with <code>AllArgsConstructor<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Data\r\n@AllArgsConstructor\r\npublic class Person {\r\n    private final String firstName;\r\n    private final String lastName;\r\n    private Integer age;\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Now we can use generated constructor in spock test:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">def 'use generated allArgsConstructor'() {\r\n    when:\r\n        Person p = new Person('John', 'Smith', 30)\r\n    then:\r\n        with(p) {\r\n            firstName == 'John'\r\n            lastName == 'Smith'\r\n            age == 30\r\n        }\r\n}<\/pre>\n<p>And the test is green.<\/p>\n<p>Let&#8217;s add new optional field to our Person class &#8211; <code>email<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Data\r\n@AllArgsConstructor\r\npublic class Person {\r\n    private final String firstName;\r\n    private final String lastName;\r\n    private Integer age;\r\n    private String email;\r\n}<\/pre>\n<p>Adding optional field is considered compatible change. But our test fails&#8230;<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.github.alien11689.allargsconstructor.Person(java.lang.String, java.lang.String, java.lang.Integer)<\/pre>\n<h2 id=\"how-to-solve-this-problem\">How to solve this problem?<\/h2>\n<h3 id=\"after-adding-field-add-previous-constructor\">After adding field add previous constructor<\/h3>\n<p>If you still want to use <code>AllArgsConstructor<\/code> you have to ensure compatibility by adding previous version of constructor on your own:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Data\r\n@AllArgsConstructor\r\npublic class Person {\r\n    private final String firstName;\r\n    private final String lastName;\r\n    private Integer age;\r\n    private String email;\r\n\r\n    public Person(String firstName, String lastName, Integer age) {\r\n        this(firstName, lastName, age, null);\r\n    }\r\n}\r\n<\/pre>\n<p>And now our test again passes.<\/p>\n<h3 id=\"annotation-lombok.data-is-enough\"><span id=\"annotation-lombok-data-is-enough\">Annotation <code>lombok.Data<\/code> is enough<\/span><\/h3>\n<p>If you use only <a href=\"https:\/\/projectlombok.org\/api\/lombok\/Data.html\"><code>Data<\/code><\/a> annotation, then constructor, with only mandatory (<code>final<\/code>) fields, will be generated. It is because <code>Data<\/code> implies <a href=\"https:\/\/projectlombok.org\/api\/lombok\/RequiredArgsConstructor.html\"><code>RequiredArgsConstructor<\/code><\/a>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Data\r\npublic class Person {\r\n    private final String firstName;\r\n    private final String lastName;\r\n    private Integer age;\r\n}<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">class PersonTest extends Specification {\r\n    def 'use generated requiredFieldConstructor'() {\r\n        when:\r\n            Person p = new Person('John', 'Smith')\r\n            p.age = 30\r\n        then:\r\n            with(p) {\r\n                firstName == 'John'\r\n                lastName == 'Smith'\r\n                age == 30\r\n            }\r\n    }\r\n}<\/pre>\n<p>After adding new field <code>email<\/code> test still passes.<\/p>\n<h3 id=\"use-builder-annotation\">Use <code>Builder<\/code> annotation<\/h3>\n<p>Annotation <a href=\"https:\/\/projectlombok.org\/api\/lombok\/Builder.html\"><code>Builder<\/code><\/a> generates for us <code>PersonBuilder<\/code> class which helps us create new <code>Person<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Data\r\n@Builder\r\npublic class Person {\r\n    private final String firstName;\r\n    private final String lastName;\r\n    private Integer age;\r\n}<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">class PersonTest extends Specification {\r\n    def 'use builder'() {\r\n        when: Person p = Person.builder()\r\n            .firstName('John')\r\n            .lastName('Smith')\r\n            .age(30).build()\r\n        then: with(p) {\r\n            firstName == 'John'\r\n            lastName == 'Smith'\r\n            age == 30\r\n        }\r\n    }\r\n}<\/pre>\n<p>After adding email field test still passes.<\/p>\n<h1 id=\"conclusion\">Conclusion<\/h1>\n<p>If you use <code>AllArgsConstructor<\/code> 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 <code>Data<\/code> or <code>Builder<\/code> annotation.<\/p>\n<p>Sources are available <a href=\"https:\/\/github.com\/alien11689\/do-no-use-allArgsConstructor\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"Introduction Do you think about compatibility of your public API when you modify classes from it? It is&hellip;\n","protected":false},"author":54,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[594,50,68],"class_list":{"0":"post-12835","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-development-design","7":"tag-api","8":"tag-groovy","9":"tag-java"},"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/12835","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/54"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=12835"}],"version-history":[{"count":11,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/12835\/revisions"}],"predecessor-version":[{"id":15670,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/12835\/revisions\/15670"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=12835"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=12835"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=12835"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}