Skip to content
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c5ed394
Rename `JavaLangAccess::*NoRepl` methods
vy Jun 20, 2025
b484510
Convert IAE-throwing methods into CCE-throwing ones
vy Jul 17, 2025
10cb72c
Improve docs of touched methods and add NPE checks
vy Jul 24, 2025
6e968a7
Merge remote-tracking branch 'upstream/master' into jlaNoRepl
vy Jul 24, 2025
5f555a6
Replace `requireNonNull` with implicit null checks
vy Jul 25, 2025
ac8e342
Merge remote-tracking branch 'upstream/master' into jlaNoRepl
vy Aug 7, 2025
1fb8582
Group `String` methods by `doReplace` argument
vy Aug 8, 2025
6fe1a9f
Avoid code duplication by sprinkling some generics magic
vy Aug 12, 2025
f536a34
Simplify added null checks
vy Aug 12, 2025
c5ddfe6
Remove redundant type parameters
vy Aug 12, 2025
f753389
Merge remote-tracking branch 'upstream/master' into jlaNoRepl
vy Aug 21, 2025
26cf5d6
Cosmetic improvements
vy Aug 21, 2025
7af0f35
Javadoc fix
vy Aug 21, 2025
1719676
Rename `NoReplTest` and fix its copyright year
vy Aug 22, 2025
01d4f87
Avoid using links in the Javadoc title line
vy Aug 22, 2025
28cbfd1
Document parametrization on the exception type
vy Aug 22, 2025
09b8f50
Improve exception parametrization
vy Aug 22, 2025
a73b446
Renamed to `malformedASCII`
vy Aug 22, 2025
788dffc
Improve comment style
vy Aug 25, 2025
584e6e2
Improve "sneaky throws"
vy Aug 25, 2025
fa46a81
Improve docs
vy Aug 28, 2025
978d981
Simplify `encodeWithEncoder` and trim long lines
vy Aug 28, 2025
14c0391
Rename `NoReplacement` suffix to `OrThrow`
vy Aug 28, 2025
b120d14
Rename `exceptionClass` to `exClass`
vy Aug 29, 2025
dae04e9
Improve Javadoc of touched `encode*()` methods
vy Aug 29, 2025
b5871ab
Merge remote-tracking branch 'upstream/master' into jlaNoRepl
vy Sep 1, 2025
a69f9fd
Fix `ClassCastException` spotted by `ReadWriteString`
vy Sep 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/io/DataInputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ public static final String readUTF(DataInput in) throws IOException {
if (ascii == utflen) {
String str;
if (trusted) {
str = JLA.uncheckedNewStringNoRepl(bytearr, StandardCharsets.ISO_8859_1);
str = JLA.uncheckedNewStringNoReplacement(bytearr, StandardCharsets.ISO_8859_1);
} else {
str = new String(bytearr, 0, utflen, StandardCharsets.ISO_8859_1);
}
Expand Down
247 changes: 139 additions & 108 deletions src/java.base/share/classes/java/lang/String.java

Large diffs are not rendered by default.

22 changes: 13 additions & 9 deletions src/java.base/share/classes/java/lang/System.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
import java.util.ResourceBundle;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Supplier;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
Expand Down Expand Up @@ -2124,28 +2123,33 @@ public Stream<ModuleLayer> layers(ClassLoader loader) {
public int countPositives(byte[] bytes, int offset, int length) {
return StringCoding.countPositives(bytes, offset, length);
}

public int countNonZeroAscii(String s) {
return StringCoding.countNonZeroAscii(s);
}
public String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException {
return String.newStringNoRepl(bytes, cs);

public String uncheckedNewStringNoReplacement(byte[] bytes, Charset cs) throws CharacterCodingException {
return String.newStringNoReplacement(bytes, cs);
}

public char uncheckedGetUTF16Char(byte[] bytes, int index) {
return StringUTF16.getChar(bytes, index);
}

public void uncheckedPutCharUTF16(byte[] bytes, int index, int ch) {
StringUTF16.putChar(bytes, index, ch);
}
public byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException {
return String.getBytesNoRepl(s, cs);

public byte[] uncheckedGetBytesNoReplacement(String s, Charset cs) throws CharacterCodingException {
return String.getBytesNoReplacement(s, cs);
}

public String newStringUTF8NoRepl(byte[] bytes, int off, int len) {
return String.newStringUTF8NoRepl(bytes, off, len, true);
public String newStringUTF8NoReplacement(byte[] bytes, int off, int len) throws CharacterCodingException {
return String.newStringUTF8NoReplacement(bytes, off, len, true);
}

public byte[] getBytesUTF8NoRepl(String s) {
return String.getBytesUTF8NoRepl(s);
public byte[] getBytesUTF8NoReplacement(String s) throws CharacterCodingException {
return String.getBytesUTF8NoReplacement(s);
}

public void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len) {
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/math/BigDecimal.java
Original file line number Diff line number Diff line change
Expand Up @@ -4150,7 +4150,7 @@ private String layoutChars(boolean sci) {
buf[highIntSize] = '.';
DecimalDigits.uncheckedPutPairLatin1(buf, highIntSize + 1, lowInt);
try {
return JLA.uncheckedNewStringNoRepl(buf, StandardCharsets.ISO_8859_1);
return JLA.uncheckedNewStringNoReplacement(buf, StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException cce) {
throw new AssertionError(cce);
}
Expand Down
4 changes: 2 additions & 2 deletions src/java.base/share/classes/java/nio/file/Files.java
Original file line number Diff line number Diff line change
Expand Up @@ -3043,7 +3043,7 @@ public static String readString(Path path, Charset cs) throws IOException {
byte[] ba = readAllBytes(path);
if (path.getClass().getModule() != Object.class.getModule())
ba = ba.clone();
return JLA.uncheckedNewStringNoRepl(ba, cs);
return JLA.uncheckedNewStringNoReplacement(ba, cs);
}

/**
Expand Down Expand Up @@ -3362,7 +3362,7 @@ public static Path writeString(Path path, CharSequence csq, Charset cs, OpenOpti
Objects.requireNonNull(csq);
Objects.requireNonNull(cs);

byte[] bytes = JLA.uncheckedGetBytesNoRepl(String.valueOf(csq), cs);
byte[] bytes = JLA.uncheckedGetBytesNoReplacement(String.valueOf(csq), cs);
if (path.getClass().getModule() != Object.class.getModule())
bytes = bytes.clone();
write(path, bytes, options);
Expand Down
12 changes: 6 additions & 6 deletions src/java.base/share/classes/java/util/HexFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ private String formatOptDelimiter(byte[] bytes, int fromIndex, int toIndex) {
}
try {
// Return a new string using the bytes without making a copy
return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
return jla.uncheckedNewStringNoReplacement(rep, StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException cce) {
throw new AssertionError(cce);
}
Expand Down Expand Up @@ -696,7 +696,7 @@ public String toHexDigits(byte value) {
rep[0] = (byte)toHighHexDigit(value);
rep[1] = (byte)toLowHexDigit(value);
try {
return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
return jla.uncheckedNewStringNoReplacement(rep, StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException cce) {
throw new AssertionError(cce);
}
Expand Down Expand Up @@ -732,7 +732,7 @@ public String toHexDigits(short value) {
rep[3] = (byte)toLowHexDigit((byte)value);

try {
return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
return jla.uncheckedNewStringNoReplacement(rep, StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException cce) {
throw new AssertionError(cce);
}
Expand Down Expand Up @@ -760,7 +760,7 @@ public String toHexDigits(int value) {
rep[7] = (byte)toLowHexDigit((byte)value);

try {
return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
return jla.uncheckedNewStringNoReplacement(rep, StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException cce) {
throw new AssertionError(cce);
}
Expand Down Expand Up @@ -796,7 +796,7 @@ public String toHexDigits(long value) {
rep[15] = (byte)toLowHexDigit((byte)value);

try {
return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
return jla.uncheckedNewStringNoReplacement(rep, StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException cce) {
throw new AssertionError(cce);
}
Expand Down Expand Up @@ -824,7 +824,7 @@ public String toHexDigits(long value, int digits) {
value = value >>> 4;
}
try {
return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1);
return jla.uncheckedNewStringNoReplacement(rep, StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException cce) {
throw new AssertionError(cce);
}
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/share/classes/java/util/UUID.java
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ public String toString() {
ByteArrayLittleEndian.setLong(buf, 28, hex8(leastSigBits));

try {
return jla.uncheckedNewStringNoRepl(buf, StandardCharsets.ISO_8859_1);
return jla.uncheckedNewStringNoReplacement(buf, StandardCharsets.ISO_8859_1);
} catch (CharacterCodingException cce) {
throw new AssertionError(cce);
}
Expand Down
18 changes: 13 additions & 5 deletions src/java.base/share/classes/java/util/zip/ZipCoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -252,12 +252,20 @@ boolean isUTF8() {

@Override
String toString(byte[] ba, int off, int length) {
return JLA.newStringUTF8NoRepl(ba, off, length);
try {
return JLA.newStringUTF8NoReplacement(ba, off, length);
} catch (CharacterCodingException cce) {
throw new IllegalArgumentException(cce);
}
}

@Override
byte[] getBytes(String s) {
return JLA.getBytesUTF8NoRepl(s);
try {
return JLA.getBytesUTF8NoReplacement(s);
} catch (CharacterCodingException cce) {
throw new IllegalArgumentException(cce);
}
}

@Override
Expand All @@ -271,9 +279,9 @@ int checkedHash(byte[] a, int off, int len) throws Exception {
// Non-ASCII, fall back to decoding a String
// We avoid using decoder() here since the UTF8ZipCoder is
// shared and that decoder is not thread safe.
// We use the JLA.newStringUTF8NoRepl variant to throw
// We use the JLA.newStringUTF8NoReplacement variant to throw
// exceptions eagerly when opening ZipFiles
return hash(JLA.newStringUTF8NoRepl(a, off, len));
return hash(JLA.newStringUTF8NoReplacement(a, off, len));
}
int h = ArraysSupport.hashCodeOfUnsigned(a, off, len, 0);
if (a[end - 1] != '/') {
Expand All @@ -289,7 +297,7 @@ private boolean hasTrailingSlash(byte[] a, int end) {
@Override
byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) {
try {
byte[] encoded = JLA.uncheckedGetBytesNoRepl(str, UTF_8.INSTANCE);
byte[] encoded = JLA.uncheckedGetBytesNoReplacement(str, UTF_8.INSTANCE);
int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len);
if (mismatch == -1) {
return EXACT_MATCH;
Expand Down
38 changes: 19 additions & 19 deletions src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java
Original file line number Diff line number Diff line change
Expand Up @@ -330,35 +330,35 @@ public interface JavaLangAccess {
* @return the newly created string
* @throws CharacterCodingException for malformed or unmappable bytes
*/
String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException;
String uncheckedNewStringNoReplacement(byte[] bytes, Charset cs) throws CharacterCodingException;

/**
* Encode the given string into a sequence of bytes using the specified
* {@linkplain java.nio.charset.Charset charset}.
* {@return the sequence of bytes obtained by encoding the given string in
* the specified {@linkplain java.nio.charset.Charset charset}}
* <p>
* <b>WARNING: This method returns the {@code byte[]} backing the provided
* {@code String}, if the input is ASCII. Hence, the returned byte array
* must not be modified.</b>
* <p>
* This method throws {@code CharacterCodingException} instead of replacing
* when malformed input or unmappable characters are encountered.
*
* @param s the string to encode
* @param cs the charset
* @return the encoded bytes
* @throws CharacterCodingException for malformed input or unmappable characters
* @throws NullPointerException If {@code s} or {@code cs} is null
* @throws CharacterCodingException For malformed input or unmappable characters
*/
byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException;
byte[] uncheckedGetBytesNoReplacement(String s, Charset cs) throws CharacterCodingException;

/**
* Returns a new string by decoding from the given UTF-8 bytes array.
* {@return a new string by decoding from the given UTF-8 bytes array}
*
* @param off the index of the first byte to decode
* @param len the number of bytes to decode
* @return the newly created string
* @throws IllegalArgumentException for malformed or unmappable bytes.
* @param offset the index of the first byte to decode
* @param length the number of bytes to decode
* @throws NullPointerException If {@code bytes} is null
* @throws StringIndexOutOfBoundsException If {@code offset} is negative,
* {@code length} is negative, or {@code offset} is greater than
* {@code bytes.length - length}
* @throws CharacterCodingException For malformed input or unmappable characters
*/
String newStringUTF8NoRepl(byte[] bytes, int off, int len);
String newStringUTF8NoReplacement(byte[] bytes, int offset, int length) throws CharacterCodingException;

/**
* Get the {@code char} at {@code index} in a {@code byte[]} in internal
Expand All @@ -384,13 +384,13 @@ public interface JavaLangAccess {
void uncheckedPutCharUTF16(byte[] bytes, int index, int ch);

/**
* Encode the given string into a sequence of bytes using utf8.
* {@return the sequence of bytes obtained by encoding the given string in UTF-8}
*
* @param s the string to encode
* @return the encoded bytes in utf8
* @throws IllegalArgumentException for malformed surrogates
* @throws NullPointerException If {@code s} is null
* @throws CharacterCodingException For malformed input or unmappable characters
*/
byte[] getBytesUTF8NoRepl(String s);
byte[] getBytesUTF8NoReplacement(String s) throws CharacterCodingException;

/**
* Inflated copy from {@code byte[]} to {@code char[]}, as defined by
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/unix/classes/sun/nio/fs/UnixPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ private static String normalize(String input, int len, int off) {
private static byte[] encode(UnixFileSystem fs, String input) {
input = fs.normalizeNativePath(input);
try {
return JLA.uncheckedGetBytesNoRepl(input, Util.jnuEncoding());
return JLA.uncheckedGetBytesNoReplacement(input, Util.jnuEncoding());
} catch (CharacterCodingException cce) {
throw new InvalidPathException(input,
"Malformed input or input contains unmappable characters");
Expand Down
12 changes: 6 additions & 6 deletions test/jdk/java/lang/String/NoReplTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -24,7 +24,7 @@
/*
* @test
* @bug 8286287 8288589
* @summary Tests for *NoRepl() shared secret methods.
* @summary Tests for *NoReplacement() shared secret methods.
* @run testng NoReplTest
* @modules jdk.charsets
*/
Expand All @@ -45,11 +45,11 @@ public class NoReplTest {
private final static Charset WINDOWS_1252 = Charset.forName("windows-1252");

/**
* Verifies newStringNoRepl() throws a CharacterCodingException.
* Verifies `uncheckedNewStringNoReplacement()` throws a `CharacterCodingException`.
* The method is invoked by `Files.readString()` method.
*/
@Test
public void newStringNoReplTest() throws IOException {
public void uncheckedNewStringNoReplacementTest() throws IOException {
var f = Files.createTempFile(null, null);
try (var fos = Files.newOutputStream(f)) {
fos.write(MALFORMED_UTF16);
Expand All @@ -67,11 +67,11 @@ public void newStringNoReplTest() throws IOException {
}

/**
* Verifies getBytesNoRepl() throws a CharacterCodingException.
* Verifies `uncheckedGetBytesNoReplacement()` throws a `CharacterCodingException`.
* The method is invoked by `Files.writeString()` method.
*/
@Test
public void getBytesNoReplTest() throws IOException {
public void uncheckedGetBytesNoReplacementTest() throws IOException {
var f = Files.createTempFile(null, null);
try {
Files.writeString(f, MALFORMED_WINDOWS_1252, WINDOWS_1252);
Expand Down