[POC] @Builder.Exclude for a field in cases where @Builder/@SuperBuilder is on a type #3723
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
relates to #2307 , #3283 , #3713
Motivation
I know that #2307 has been closed but from the discussion thread I realized that many others were having the same issues I was: that some fields need not be part of a builder (or whatever creation pattern the class is using).
I understand that there is the option of creating a static method/constructor and annotating it with
@Builder
to achieve exclusion of field(s). However, I would argue that a similar argument could have been made for default values as well. Yet, we have a@Builder.Default
which is a super useful feature to have!My use cases specifically was with regards to JPA Entity classes where I wanted to hide certain non-insertable/non-updatable fields in a JPA Entity from users attempting to build an Entity object. While using
@Setter
, this was simple enough with@Setter(AccessLevel.PRIVATE)
, but I wanted to use@Builder
since the entities were large and complex. There I had no options with regards to excluding these fields. Not excluding them would mislead the users since such fields are not persisted in the database even when initialized so I was forced to use Setters.I did not want to badger the maintainers with excessive argumentation so I thought a "POC" might better demonstrate what such an idea would like and would take the discussion forward more constructively. I would greatly appreciate any and all feedback.
Implementation
The basic idea is that if the
@Builder
/@SuperBuilder
annotation is on a type, no setter methods will be generated in the builder for the fields marked with@Builder.Exclude
. This means that although the builder class will contain all the fields(so as not to break any existing logic of mapping the builder class to the annotated class through a constructor, generated for builder or maybe through@AllAgsConstructor
). However, it will not be possible to set the value of the excluded field before calling the build() method.It is somewhat similar in use(not implementation) to
@Builder.Default
:The builder for this class will not contain a
User.UserBuilder id(int id)
method.I've added a warning similar to the one for
@Builder.Default
for when the annotation is not on type. As is the case with@Builder.Default
, the@Builder.Exclude
annotation holds no meaning when used without a@Builder
on the type. if the@Builder
is on a constructor or a static method, the exclusion will not take placeI've added a few test cases to demonstrate its working.
I'll add more test cases to the PR if the direction looks promising!