Skip to content

Commit fa20d34

Browse files
Add UTF-8 validation documentation and tests for proto2, proto3, and editions for Java Protobuf
PiperOrigin-RevId: 931326656
1 parent 8667063 commit fa20d34

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
+++
2+
title = "UTF-8 Validation in Java"
3+
weight = 650
4+
linkTitle = "UTF-8 Validation in Java"
5+
description = "Describes the UTF-8 string behavior in Java protobuf across all syntaxes, editions, and option/feature settings."
6+
type = "docs"
7+
+++
8+
9+
.
10+
11+
Proto2 has both string and bytes, and from the beginning it was documented
12+
that strings must always contain UTF-8 encoded text.
13+
Enforcement of this requirement varies from language to language (details later
14+
in this topic), which means that in practice, many string fields contain
15+
non-UTF-8 data despite what the spec says.
16+
17+
For proto3 it was decided that all parsers must validate UTF-8. This
18+
decision came almost a year after proto3 had debuted in
19+
google3, so this change required
20+
a project to set
21+
`enforce_utf8=false` on all existing string fields before flipping the default
22+
to `enforce_utf8=true`. It was a goal of the LSC to burn down all uses of
23+
`enforce_utf8=false` and ultimately remove the
24+
option.
25+
26+
Here is a summary of UTF-8 validation behavior for Java Protobuf across syntaxes
27+
and editions. This behavior is consistent for both standard string fields and
28+
string-typed extensions:
29+
30+
Syntax / Edition | `features.utf8_validation` | `features.(pb.java).utf8_validation` | `java_string_check_utf8` | `enforce_utf8` | Java UTF-8 Validation Behavior
31+
:---------------------- | :-------------------------- | :-------------------------------------- | :------------------------- | :------------------------ | :-----------------------------
32+
**proto2** | *Disallowed* | *Disallowed* | unset or `false` (default) | *Ignored* | **No validation** (proto2 default)
33+
**proto2** | *Disallowed* | *Disallowed* | `true` | *Ignored* | **Validation enabled***
34+
**proto3** | *Disallowed* | *Disallowed* | *Ignored* | unset or `true` (default) | **Validation enabled** (proto3 default)
35+
**proto3** | *Disallowed* | *Disallowed* | *Ignored* | `false` | **No validation**
36+
**Edition 2023 / 2024** | unset or `VERIFY` (default) | unset, `DEFAULT` (default), or `VERIFY` | *Disallowed* | *Disallowed* | **Validation enabled**** (editions default)
37+
**Edition 2023 / 2024** | `NONE` | unset or `DEFAULT` (default) | *Disallowed* | *Disallowed* | **No validation**
38+
**Edition 2023 / 2024** | `NONE` | `VERIFY` | *Disallowed* | *Disallowed* | **Validation enabled** (validation in Java only)
39+
40+
\* In Java Lite, `proto2` string-typed extensions are **not** validated when
41+
`java_string_check_utf8=true`.
42+
43+
\** In Java Lite, under edition 2023 and 2024, string-typed extensions are
44+
**not** validated under any combination of options. This is an oversight that
45+
should be corrected in a future
46+
edition.
47+
48+
### Unvalidated Behavior
49+
50+
JavaLite and Java have the same API for string fields, but use different object
51+
representations:
52+
53+
* **String-Only:** JavaLite always stores strings as `java.lang.String`. This
54+
means that the field cannot preserve invalid UTF-8. If invalid UTF-8 is
55+
parsed or assigned via `setFoo(ByteString)`, it immediately undergoes a
56+
lossy conversion to replacement characters.
57+
* **Dual Mode:** Java "full" supports a dual representation, where the
58+
`java.lang.Object` field can be either `java.lang.String` or
59+
`java.lang.ByteString`. This means that invalid UTF-8 can be preserved when
60+
we parse proto2, and `ByteString getFooBytes()` will return whatever was
61+
parsed off the wire.
62+
63+
### Legacy Options
64+
65+
- **`java_string_check_utf8`** is a **file-level option** applicable only to
66+
`proto2`. This option can be set in a proto3 file, but it will have no
67+
effect. Java Lite does **not** validate string-typed extensions.
68+
- **`enforce_utf8`** is a **field-level option** applicable only to `proto3`.
69+
Setting it to `false` is the only way to disable validation in proto3, but
70+
it is deprecated and subject to removal (and requires being on an
71+
allowlist). This option can be set in a proto2 file, but it will have no
72+
effect.
73+
- Both legacy options are **disallowed under Editions**, where you must use
74+
the features framework instead.
75+
76+
### Editions Features
77+
78+
- **`features.utf8_validation`** is a file- or field-level feature to control
79+
UTF-8 validation for **all** languages.
80+
- **`features.(pb.java).utf8_validation`** is a file- or field-level feature
81+
to control UTF-8 validation for **Java Only**. The default is to use
82+
`features.utf8_validation` for Java. This feature should be phased out in
83+
favor of `features.utf8_validation`.
84+
- Both features are **disallowed under proto2 and proto3** (as are all
85+
editions features).

0 commit comments

Comments
 (0)