1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
Subject: Update String access in StringUtils
Date: Thu, 28 Feb 2019 13:55:04 +0100
From: Andrej Shadura <andrewsh@debian.org>
See https://stackoverflow.com/questions/52620885/string-to-object-conversion-not-working-in-java-11:
> The message “class [B cannot be cast to class [C” indicates that
> the method is trying to cast a byte[] array to a char[] array. Since
> the code location also has a name like FastStringUtils.toCharArray,
> I can guess what happens here.
>
> This class seems to hack into the java.lang.String class and read its
> value field in a questionable attempt of performance improvement. Since
> Java 9, this internal array is a byte[] array instead of a char[] array,
> which makes this hack fail at runtime.
Initially based on:
commit a8af29f932d73d8d1c6e44e49b68f9bb44905685
Author: Peter Lawrey <peter.lawrey@higherfrequencytrading.com>
Date: Wed Mar 2 14:00:44 2016 +0000
Tuning FIX to minimise garbage.
--- a/src/main/java/net/openhft/chronicle/core/util/StringUtils.java
+++ b/src/main/java/net/openhft/chronicle/core/util/StringUtils.java
@@ -19,7 +19,6 @@
import net.openhft.chronicle.core.annotation.ForceInline;
import org.jetbrains.annotations.NotNull;
-import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import static java.lang.Character.toLowerCase;
@@ -30,14 +29,11 @@
public enum StringUtils {
;
- private static final Constructor<String> STRING_CONSTRUCTOR;
private static final Field S_VALUE, SB_VALUE, SB_COUNT;
private static final long MAX_VALUE_DIVIDE_10 = Long.MAX_VALUE / 10;
static {
try {
- STRING_CONSTRUCTOR = String.class.getDeclaredConstructor(char[].class, boolean.class);
- STRING_CONSTRUCTOR.setAccessible(true);
S_VALUE = String.class.getDeclaredField("value");
S_VALUE.setAccessible(true);
SB_VALUE = Class.forName("java.lang.AbstractStringBuilder").getDeclaredField("value");
@@ -93,6 +89,10 @@
public static char[] extractChars(StringBuilder sb) {
try {
return (char[]) SB_VALUE.get(sb);
+ } catch (ClassCastException e) {
+ final char[] data = new char[sb.length()];
+ sb.getChars(0, sb.length(), data, 0);
+ return data;
} catch (IllegalAccessException | IllegalArgumentException e) {
throw new AssertionError(e);
}
@@ -101,6 +101,8 @@
public static char[] extractChars(String s) {
try {
return (char[]) S_VALUE.get(s);
+ } catch (ClassCastException e) {
+ return s.toCharArray();
} catch (IllegalAccessException | IllegalArgumentException e) {
throw new AssertionError(e);
}
@@ -115,11 +117,7 @@
}
public static String newString(char[] chars) {
- try {
- return STRING_CONSTRUCTOR.newInstance(chars, true);
- } catch (Exception e) {
- throw new AssertionError(e);
- }
+ return new String(chars);
}
public static String firstLowerCase(String str) {
|