|
| 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