chore: replace deprecated String constructor in StringTools - #1230
Open
pjfanning wants to merge 1 commit into
Open
chore: replace deprecated String constructor in StringTools#1230pjfanning wants to merge 1 commit into
pjfanning wants to merge 1 commit into
Conversation
Motivation: StringTools.asciiStringFromBytes used the deprecated `new String(byte[], int)` behind a @nowarn, justified by a comment saying it was "the fastest way to convert a ASCII encoded byte array into a String without extra copying". That was true on Java 8, where the alternative expanded the bytes into a char array. Since JDK 9 and compact strings it is not, and this branch requires JDK 17. The method is on the HTTP/2 HPACK decode path, so it is worth being sure the replacement is neither a behaviour nor a performance change. Modification: Decode with ISO-8859-1, which maps every byte to the character of the same value, exactly as the deprecated constructor did with hibyte 0. Not US-ASCII, which would turn bytes above 0x7F into replacement characters; HPACK string literals are opaque octets. Drops the @nowarn and the scala.annotation.nowarn import, and reuses the ISO88591 constant already in this package. Result: No deprecated JDK API and no misleading comment, with identical behaviour. Tests: - New StringToolsSpec pins the byte to character mapping across the whole 0x00 to 0xFF range, which is what would break if the charset were changed to US-ASCII later. It is a regression guard, not a failing-before test: this change is deliberately behaviour preserving - Verified in jshell that the two forms produce equal Strings for all 256 byte values - JMH, average time over sizes 12, 64 and 4096 bytes: 25.3 / 30.2 / 1260.2 ns for the deprecated form against 28.2 / 43.1 / 952.7 ns for ISO-8859-1, error bars overlapping at every size, so no measurable difference either way - sbt "http-core / Test / testOnly org.apache.pekko.http.impl.util.StringToolsSpec" - 4 passed - sbt http-core/mimaReportBinaryIssues - clean - scalafmt --mode diff-ref=upstream/main - clean References: None - found while reviewing the code base against the JDK 17 baseline
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
StringTools.asciiStringFromBytesuses the deprecatednew String(byte[], int hibyte)behind a@nowarn, justified by this comment:That was true on Java 8, where the alternative expanded the bytes into a
char[]. It stopped being true with JDK 9 and compact strings, and this branch requires JDK 17.The method sits on the HTTP/2 HPACK decode path (
shaded/com/twitter/hpack/Decoder.readStringLiteral), so it is worth being sure the replacement changes neither behaviour nor performance.Modification
plus dropping the now-unused
scala.annotation.nowarnimport.ISO88591is the constant already defined in this package (impl/util/package.scala).ISO-8859-1, not US-ASCII, despite the method name.
new String(bytes, 0)setschar = byte & 0xFFfor every byte; ISO-8859-1 does exactly the same, so the two agree on every possible input. US-ASCII would turn bytes above 0x7F intoU+FFFD, and HPACK string literals are opaque octets (RFC 7541), so such bytes really can arrive here. This matches the same decision made forasciiStringin the parser.Result
No deprecated JDK API, no
@nowarn, and no misleading Java-8-era comment, with identical behaviour.I did not want to take the "compact strings make these identical" reasoning on trust, so:
Strings for all 256 byte values.new String(bytes, 0)new String(bytes, ISO_8859_1)Error bars overlap at every size, so there is no measurable difference in either direction. (A crude jshell loop first suggested the charset form was ~2x slower at small sizes; that turned out to be warmup/ordering noise, which is why this was re-measured under JMH.)
Tests
StringToolsSpecpins the byte-to-character mapping across the whole 0x00-0xFF range - the property that would break if someone later "corrected" the charset to US-ASCII to match the method name - plus a round-trip throughasciiStringBytesand the empty-array case.sbt "http-core / Test / testOnly org.apache.pekko.http.impl.util.StringToolsSpec"- 4 passed. It is a regression guard, not a failing-before test; this change is deliberately behaviour preserving, so nothing can fail against it.sbt http-core/mimaReportBinaryIssues- clean.scalafmt --mode diff-ref=upstream/main- clean.http2-testssuite that exercises the HPACK codec end to end; leaving that to CI.References
None - found while reviewing the code base against the JDK 17 baseline