_Migrated from Google Code (issue 748)_
:bust_in_silhouette: Konstantin.Lepa :clock8: Oct 25, 2014 at 20:21 UTC
Hi,
For example, the feature would be helpful for JPA:
@ Entity
@ Setter @ Getter
@ Builder
public class TrainingPlan {
/* ... */
@ OneToMany
private List<Workout> workouts;
// It's needed for correct work of a bidirectional relationship!
public void setWorkouts(List<Workout> workouts) {
this.workouts = workouts;
workouts.stream().forEach(w -> w.setTrainingPlan(this));
}
/* ... */
}
So, lombok would generate next code:
/* ... */
public TrainingPlan build() {
TrainingPlan trainingPlan = new TrainingPlan();
trainingPlan.setWorkouts(workouts);
/* ... */
return trainingPlan;
}
/* ... */
Thanks
_End of migration_
This feature would be great. It also eliminate another limitation of the builder which is losing all the default values, i.e.: collections are usually initialized in the declaration or in the default constructor; by having an all args constructor supporting the builder you have the chance of initializing an object with an null collection inside.
The setter-based builder would only set the available values, you could also protect your setter and ignore null values on collections. It is a win-win.
@jrglee solving the 'default value issue' is a separate problem; we certainly wouldn't want to encourage lombok users to give their classes setters (even private ones) JUST to enable defaults. In fact, potential abuse means I'm less inclined to make this feature request happen.
Accepted, but because of the issue raised by @jrglee, blocked until we solve the need for defaults in builder.
We can probably just do the right thing by default if you have either an explicit no-args constructor OR you have no constructors, AND @NoArgsConstructor and no other @XArgsConstructor on the class. In that case we'll just build-by-setter instead.
NB: To work around this, you can make a static method that constructs a new instance and then calls .set() for everything; then put @Builder on that. Alternatively, make an all-args constructor and do the same thing. Then put @Builder on that.
@rzwitserloot Few months after I wrote my last comment I learned how to use the toBuilder method. Something like
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Foo {
@Getter
private String greeting = "hello";
public static FooBuilder builder() {
return new Foo().toBuilder();
}
}
In this way I can call builder without having to provide a value to greeting. It solves the default value issue and even preserves immutability in my example. I learned this trick while reading about another issue. It would be nice to have this example in the main documentation too.
Hi, I am also facing a situation when this feature would be useful, the one in the title I mean. I am using both @Data and @Builder on my data object and am creating a custom setter for one of the fields, setter which does a slight transformation on the value before assigning it to the field. When using the JavaBeans pattern it is fine, my value is transformed when the setter is called. But this does not happen when using the builder. The setter is bypassed in this case. Do you have a suggestion for this case, is there an "elegant" solution for this or just workarounds? Please suggest the best workaround (except duplicating code in the builder method) in this last case. Thank you.
The elegant solution is to never use setters if at all possible. ;-)
Write a constructor, put a Builder annotation on it, replace the Data
annotation with a Value annotation, never look back.
On Thu, Jun 28, 2018 at 5:01 PM, ioan-miklosik-sv notifications@github.com
wrote:
Hi, I am also facing a situation when this feature would be useful, the
one in the title I mean. I am using both @DaTa https://github.com/DaTa
and @builder https://github.com/builder on my data object and am
creating a custom setter for one of the fields, setter which does a slight
transformation on the value before assigning it to the field. When using
the JavaBeans pattern it is fine, my value is transformed when the setter
is called. But this does not happen when using the builder. The setter is
bypassed in this case. Do you have a suggestion for this case, is there an
"elegant" solution for this or just workarounds? Please suggest the best
workaround (except duplicating code in the builder method) in this last
case. Thank you.—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/rzwitserloot/lombok/issues/783#issuecomment-401065547,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAKCRfgk2hE6qtMJVDd1zyWA2e9y-vf1ks5uBO-3gaJpZM4HSv0Z
.
--
"Don't only practice your art, but force your way into it's secrets, for it
and knowledge can raise men to the divine."
-- Ludwig von Beethoven
between @Builder.Default and toBuilder=true, the use cases are adequately addressed. We won't add this feature.
The elegant solution is to never use setters if at all possible. ;-) Write a constructor, put a Builder annotation on it, replace the Data annotation with a Value annotation, never look back.
@randakar I like your idea with "no setters at all". There is an issue when writing the constructor manually. The @Builder.Default seems to not work then. What do you advise?
@baldram I'm not sure, IIUYC, but I guess, with a manual constructor, you can just leave out both @Builder.Default and the initializer expression and initialize the field in the constructor.
The trick from the above https://github.com/rzwitserloot/lombok/issues/783#issuecomment-281441785 may also help. In case, you dislike new Foo(), then you can use a private static final Foo instance.
That's it! You're right @Maaartinus. The Builder.Default is simply redundant in this case. I have a classic initialization and it's even more clear.
Now let's take @rzwitserloot suggestion. Finally, it looks good. Using @Builder annotation on constructor in combination with toBuilder=true I'm able to do what I need. What was my problem to solve? Updating Hibernate references in case of bidirectional mapping. All done respecting immutability! :-)
If anyone knows a way to define hibernate models without having to resort to setters and a no-args constructor, I'm all ears. Immutable classes and hibernate seems to be fully mutually incompatible.
Most helpful comment
The elegant solution is to never use setters if at all possible. ;-)
Write a constructor, put a Builder annotation on it, replace the Data
annotation with a Value annotation, never look back.
On Thu, Jun 28, 2018 at 5:01 PM, ioan-miklosik-sv notifications@github.com
wrote:
--
"Don't only practice your art, but force your way into it's secrets, for it
and knowledge can raise men to the divine."
-- Ludwig von Beethoven