Closed yevhenii-nadtochii closed 1 week ago
@armiol @alexander-yevsyukov
We should settle down on the option specification before proceeding with this PR. I've examined the generated code, and the main disappointment is that Protobuf v3 doesn't store explicit information about whether the field was set (except for optional
fields). Our implementation checks that the current field value is default for the field type, only then allowing a new one to set.
In general, Protobuf builders provide three paths to modify the message.
set...()
:
setName(String name)
.setName(ByteString name)
for string
and setMyEnumValue(int value)
for enums.setStudent(StudentBuilder builder)
.setField(FieldDescriptor, Object)
.merge...()
:
mergeName(Name value)
.mergeFrom(Student other)
.mergeFrom(byte[] data)
.clear...()
:
clearName()
.clear()
.The questions are the following:
bytes
arrays are also allowed.(set_once)
is specified.merge
-based mutations. Looks safe for setters as well.clear()
then? – I suggest considering merge
and clear
service methods, and don't touch them at all. Only fix the fact that for some types, merge
redirect to setters. We can introduce private unsafe setters for that, for example.
- Should we allow a custom error message for this option?
This is highly desirable. People creating their domain language would want to explain why a field can be set only once. These cases are usually non-trivial.
- Which field types are supported? - I suggest messages, enumerations and all primitives excluding repeated fields and maps. bytes arrays are also allowed.
I concur.
- Which points of message mutation does the option cover? – All setters for sure. But should we cover merging and clearing?
Merging — it is desirable.
See on clearing below.
... And clearing allows overriding a field value, for which (set_once) is specified.
The (set_once)
option largely protects from setting the value via a setter. If the developer explicitly calls clear()
it corresponds to starting all over on this message. Something happened in the domain, which cased the code to clear the message. To me it close to having newBuilder()
. I suggest viewing clear()
this way.
- Should we allow the field to be set to the current value?
I think this way it's understandable and safe. We should allow this, provided this is documented in the option documentation.
- Should we prohibit clearing of a specific field if it is marked with the option?
Let's allow clearing such fields. Please also see my earlier comment regarding the clear operation.
What about the builder clear() then?
We should allow this. See my earlier comment on the "weight" of the clear operation.
@armiol, FYI.
Attention: Patch coverage is 0.45045%
with 221 lines
in your changes missing coverage. Please review.
Project coverage is 34.21%. Comparing base (
52a2648
) to head (6994ce4
). Report is 97 commits behind head on master.
@armiol @alexander-yevsyukov PTAL
@alexander-yevsyukov @armiol PTAL
This PR extends coverage of validation codegen to support
(set_once)
constraint.The option is enforced by checking (during a field value assignment) that the current value is either default for the field type OR it is the same with the assigned one. Otherwise, the validation exception is thrown right away.
When one or more fields with the message are marked with the option, the following groups of methods are modified to add the precondition checks:
set...()
methods for the marked field.merge...()
methods, except forAbstractMessage.mergeFrom(final Message other)
. In merge methods, only parts relevant to the marked fields are affected.AbstractMessage.mergeFrom(final Message other)
This method is not explicitly supported, though it might be workable.
Supported field types
All primitives, enums and messages are supported.
An attempt to mark
repeated
ormap
field leads to an exception.