Skip to content

Commit c35d931

Browse files
glasstigerclaude
andcommitted
Fix Java 8 build breaks in OIDC device flow
The JDK 8 CI job failed to compile two Java 9+ constructs that a local JDK 25 build silently accepts (newer rt.jar has the APIs, and -source without --release does not enforce the Java 8 platform): - Utf16Sink declared a private interface method, putUnicodeEscape, a Java 9 feature. Move it to DisplaySafe as a package-private static helper, putUnicodeEscape(Utf16Sink, int); the two putAsPrintable overloads now call it. DisplaySafe already owns the display-escaping policy and shares the package, so the helper stays out of the public API. The escape logic is moved verbatim. - OidcDeviceAuth.urlEncode called URLEncoder.encode(String, Charset), a Java 10 overload. Switch to the Java 8 encode(String, String) form and catch the (unreachable for UTF-8) UnsupportedEncodingException. Verified: the three changed files compile under --release 8, the full core module compiles, and LineSenderExceptionTest, LineHttpSenderErrorResponseTest, JsonLexerTest and OidcDeviceAuthTest stay green (156 tests). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5dd82b4 commit c35d931

3 files changed

Lines changed: 30 additions & 23 deletions

File tree

core/src/main/java/io/questdb/client/cutlass/auth/OidcDeviceAuth.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@
4545
import io.questdb.client.std.str.DirectUtf8Sequence;
4646
import io.questdb.client.std.str.StringSink;
4747

48+
import java.io.UnsupportedEncodingException;
4849
import java.net.URLEncoder;
49-
import java.nio.charset.StandardCharsets;
5050
import java.util.concurrent.locks.ReentrantLock;
5151

5252
/**
@@ -885,7 +885,13 @@ private static boolean settingsChannelIsPlaintext(Endpoint server) {
885885
}
886886

887887
private static String urlEncode(String value) {
888-
return URLEncoder.encode(value, StandardCharsets.UTF_8);
888+
try {
889+
// the Charset overload is Java 10; the client targets Java 8, so use the String-charset form
890+
return URLEncoder.encode(value, "UTF-8");
891+
} catch (UnsupportedEncodingException e) {
892+
// UTF-8 is guaranteed present on every JVM, so this is unreachable; rethrow defensively
893+
throw new OidcAuthException(e).put("UTF-8 encoding is not supported");
894+
}
889895
}
890896

891897
private static void validateEndpointOrigins(Endpoint tokenEndpoint, Endpoint deviceAuthorizationEndpoint, Endpoint issuer) {

core/src/main/java/io/questdb/client/std/str/DisplaySafe.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
package io.questdb.client.std.str;
2626

27+
import static io.questdb.client.std.Numbers.hexDigits;
28+
2729
/**
2830
* Shared classifier for whether a code point is safe to show in a terminal or a log line. It is the one
2931
* source of truth for the client's display-escaping: {@link Utf16Sink#putAsPrintable(CharSequence)} escapes
@@ -71,4 +73,22 @@ public static boolean isDisplaySafe(int cp) {
7173
public static boolean isUnsafeForDisplay(int cp) {
7274
return !isDisplaySafe(cp);
7375
}
76+
77+
// Escapes a code point to one (BMP) or two (supplementary, as its surrogate pair) visible \\uXXXX
78+
// sequences, so the escaped value still names the original char. Emitting all four hex digits keeps a
79+
// char above U+00FF (e.g. U+202E) correct rather than truncated to its low byte. A static helper here
80+
// (not a private method on Utf16Sink) keeps the source Java 8 - private interface methods are Java 9.
81+
static void putUnicodeEscape(Utf16Sink sink, int cp) {
82+
if (cp > 0xFFFF) {
83+
putUnicodeEscape(sink, Character.highSurrogate(cp));
84+
putUnicodeEscape(sink, Character.lowSurrogate(cp));
85+
return;
86+
}
87+
sink.put('\\');
88+
sink.put('u');
89+
sink.put(hexDigits[(cp >> 12) & 0xF]);
90+
sink.put(hexDigits[(cp >> 8) & 0xF]);
91+
sink.put(hexDigits[(cp >> 4) & 0xF]);
92+
sink.put(hexDigits[cp & 0xF]);
93+
}
7494
}

core/src/main/java/io/questdb/client/std/str/Utf16Sink.java

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626

2727
import org.jetbrains.annotations.Nullable;
2828

29-
import static io.questdb.client.std.Numbers.hexDigits;
30-
3129
/**
3230
* Family of sinks that write out <b>character</b> value as UTF16 encoded bytes. This interface
3331
* is separate from {@link CharSink} to achieve two goals:
@@ -58,7 +56,7 @@ default void putAsPrintable(CharSequence nonPrintable) {
5856
put(nonPrintable.charAt(i + j));
5957
}
6058
} else {
61-
putUnicodeEscape(cp);
59+
DisplaySafe.putUnicodeEscape(this, cp);
6260
}
6361
i += count;
6462
}
@@ -71,7 +69,7 @@ default void putAsPrintable(char c) {
7169
if (DisplaySafe.isDisplaySafe(c)) {
7270
put(c);
7371
} else {
74-
putUnicodeEscape(c);
72+
DisplaySafe.putUnicodeEscape(this, c);
7573
}
7674
}
7775

@@ -102,21 +100,4 @@ default Utf16Sink putNonAscii(long lo, long hi) {
102100
Utf8s.utf8ToUtf16(lo, hi, this);
103101
return this;
104102
}
105-
106-
// Escapes a code point to one (BMP) or two (supplementary, as its surrogate pair) visible \\uXXXX
107-
// sequences, so the escaped value still names the original char. Emitting all four hex digits keeps a
108-
// char above U+00FF (e.g. U+202E) correct rather than truncated to its low byte.
109-
private void putUnicodeEscape(int cp) {
110-
if (cp > 0xFFFF) {
111-
putUnicodeEscape(Character.highSurrogate(cp));
112-
putUnicodeEscape(Character.lowSurrogate(cp));
113-
return;
114-
}
115-
put('\\');
116-
put('u');
117-
put(hexDigits[(cp >> 12) & 0xF]);
118-
put(hexDigits[(cp >> 8) & 0xF]);
119-
put(hexDigits[(cp >> 4) & 0xF]);
120-
put(hexDigits[cp & 0xF]);
121-
}
122103
}

0 commit comments

Comments
 (0)