Closed dpew closed 6 years ago
I think it's a nice idea. I can imagine that too:
ImmutableClazz im = ImmutableClazz.builder()
.withFirstField(30)
.withSecondField(Long.MIN_VALUE)
.build();
ImmutableClazz imCopy = ImmutableClazz.builder()
.immutableClass(im)
.withSecondField(Long.MAX_VALUE)
.build();
Thanks for creating this feature request, I can see how this use-case would be quite useful in certain situations. I'll look into the implementation.
Some considerations
:question: Builder generator is capable of adding fields from the super class' constructor to the builder as per #30, but these fields are usually not accessible from the type instance directly (because they might be private, etc.) Options
:question: Does it make sense to add this feature for staged builder as well?
:white_check_mark: Most likely not, since the builder generator cannot know, which field the user might also want to set (aka. where to start the field setting). If starting from the first field, the user would have to override the copied fields.
:question: Which method to use? Method mentioned by @shark300
Pro:
Clazz.builder().from(otherInstane).withNewField(value).build()
simpler to implement, builder regenerating (code removing) does not need to be changed, one method instead of two
Cons:
from
could be called after setting field, thereby overriding those fields Clazz.builder().withValue(value).from(otherInstance).build()
. This would be impossible with constructor.@dpew Unless you have objection, I think I will go with a copy method instead of constructor.
A convenience method could be still generated that will just do: return new Builder().from(other);
If I understood you correctly plugin will generate a method.
It's an edge case but if I modified configuration from with[FieldName] to [fieldName], plugin will generate that:
private Type from;
private String name;
public Builder from(Type type) {
this.from = type.from;
this.name = type.name;
}
public Builder from(Type type) {
this.from = type.from;
}
Is it the expected behavior?
Well reasoned.
I understand the reason for conditionally omitting the from
builder method when not feasible (super constructor params).
As for the from
method. It seems elegant and provides the capability as suggested. However given the above edge-case cited by @shark300 and the fact that from(other)
overwrites existing values, it seems as if the optimal solution is to (conditionally) generate a new builder populated from the old instance.
@shark300 Thanks for bringing that case up. That seems quite rare, though those settings are reasonable for builder generation.
@dpew Good points, after some more though I reconsidered and agree that a constructor is the way to go. But to be honest, I'm not really a fan of the instance method to create the builder. Seems like it changes the original usage, and semantically I think it's not the instance's responsibility to know how to create a builder based on itself.
What is your opinion about something like this:
Clazz.builderFrom(originalInstance).withSecondField(...).build();
Basically the same as yours, but instead of instance method I would use a static builder creator method.
Agreed. It nicely complements the Clazz.builder()
factory method.
Hi @dpew and @shark300!
The 0.0.14 release contains this change. Please update and check if everything is working as expected.
Please note, that the new copy method is not enabled by default. You can enable it in the preferences (Window->Preferences->Java->Spark Builder Generator)
@helospark
Version 0.0.14 works great. Created this new code:
ImmutableClazz c1 = ImmutableClazz.builder().withFirstField(100).withSecondField(Long.MAX_VALUE).build();
ImmutableClazz c2 = ImmutableClazz.builderFrom(c1).withSecondField(Long.MIN_VALUE).build();
Thanks for the quick response adding this useful feature. Doug
A use case suggestion: the ability to generate a builder from an instance. This way one can create new instances of immutable classes. Like this:
The builder generator would produce something like this:
And many thanks for this huge time-saving plugin. :+1: