Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
334 changes: 226 additions & 108 deletions src/java.base/share/classes/java/lang/String.java

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions src/java.base/share/classes/java/lang/System.java
Original file line number Diff line number Diff line change
Expand Up @@ -2124,6 +2124,7 @@ 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);
}
Expand All @@ -2132,21 +2133,24 @@ public String uncheckedNewStringWithLatin1Bytes(byte[] bytes) {
return String.newStringWithLatin1Bytes(bytes);
}

public String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException {
return String.newStringNoRepl(bytes, cs);
public String uncheckedNewStringOrThrow(byte[] bytes, Charset cs) throws CharacterCodingException {
return String.newStringOrThrow(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[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException {
return String.getBytesOrThrow(s, cs);
}

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

public void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len) {
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.uncheckedNewStringOrThrow(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.uncheckedGetBytesOrThrow(String.valueOf(csq), cs);
if (path.getClass().getModule() != Object.class.getModule())
bytes = bytes.clone();
write(path, bytes, options);
Expand Down
12 changes: 7 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 @@ -256,15 +256,19 @@ String toString(byte[] ba, int off, int length) {
try {
// Copy subrange for exclusive use by the string being created
byte[] bytes = Arrays.copyOfRange(ba, off, off + length);
return JLA.uncheckedNewStringNoRepl(bytes, StandardCharsets.UTF_8);
return JLA.uncheckedNewStringOrThrow(bytes, StandardCharsets.UTF_8);
} catch (CharacterCodingException cce) {
throw new IllegalArgumentException(cce);
}
}

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

@Override
Expand All @@ -278,8 +282,6 @@ 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
// exceptions eagerly when opening ZipFiles
return hash(toString(a, off, len));
}
int h = ArraysSupport.hashCodeOfUnsigned(a, off, len, 0);
Expand All @@ -296,7 +298,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.uncheckedGetBytesOrThrow(str, UTF_8.INSTANCE);
int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len);
if (mismatch == -1) {
return EXACT_MATCH;
Expand Down
24 changes: 10 additions & 14 deletions src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.function.BiFunction;
import java.util.stream.Stream;

import jdk.internal.loader.NativeLibraries;
Expand Down Expand Up @@ -332,7 +331,7 @@ public interface JavaLangAccess {

/**
* Constructs a new {@code String} by decoding the specified byte array
* using the specified {@linkplain java.nio.charset.Charset charset}.
* using the specified {@code Charset}.
* <p>
* <b>WARNING: The caller of this method shall relinquish and transfer the
* ownership of the byte array to the callee</b>, since the latter will not
Expand All @@ -343,25 +342,22 @@ public interface JavaLangAccess {
* @return the newly created string
* @throws CharacterCodingException for malformed or unmappable bytes
*/
String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException;
String uncheckedNewStringOrThrow(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 {@code 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 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[] uncheckedGetBytesOrThrow(String s, Charset cs) throws CharacterCodingException;

/**
* Get the {@code char} at {@code index} in a {@code byte[]} in internal
Expand All @@ -387,13 +383,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[] getBytesUTF8OrThrow(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.uncheckedGetBytesOrThrow(input, Util.jnuEncoding());
} catch (CharacterCodingException cce) {
throw new InvalidPathException(input,
"Malformed input or input contains unmappable characters");
Expand Down
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) 2022, 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,8 +24,8 @@
/*
* @test
* @bug 8286287 8288589
* @summary Tests for *NoRepl() shared secret methods.
* @run testng NoReplTest
* @summary Tests for *OrThrow() shared secret methods.
* @run testng OrThrowTest
* @modules jdk.charsets
*/

Expand All @@ -39,17 +39,17 @@
import org.testng.annotations.Test;

@Test
public class NoReplTest {
public class OrThrowTest {
private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00};
private final static String MALFORMED_WINDOWS_1252 = "\u0080\u041e";
private final static Charset WINDOWS_1252 = Charset.forName("windows-1252");

/**
* Verifies newStringNoRepl() throws a CharacterCodingException.
* The method is invoked by `Files.readString()` method.
* Verifies {@code uncheckedNewStringOrThrow()} throws a {@link CharacterCodingException}.
* The method is invoked by {@code Files.readString()} method.
*/
@Test
public void newStringNoReplTest() throws IOException {
public void uncheckedNewStringOrThrowTest() 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.
* The method is invoked by `Files.writeString()` method.
* Verifies {@code uncheckedGetBytesOrThrow()} throws a {@link CharacterCodingException}.
* The method is invoked by {@code Files.writeString()} method.
*/
@Test
public void getBytesNoReplTest() throws IOException {
public void uncheckedGetBytesOrThrowTest() throws IOException {
var f = Files.createTempFile(null, null);
try {
Files.writeString(f, MALFORMED_WINDOWS_1252, WINDOWS_1252);
Expand Down