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 package org.spf4j.base;
33
34 import java.lang.invoke.MethodHandle;
35 import java.lang.invoke.MethodHandles;
36 import java.lang.reflect.Constructor;
37 import java.lang.reflect.Field;
38 import java.security.AccessController;
39 import java.security.PrivilegedAction;
40 import java.util.logging.Level;
41 import java.util.logging.Logger;
42
43
44
45
46
47
48 public final class UnsafeString {
49
50
51
52
53 private static final MethodHandle CHARS_FIELD_GET;
54
55
56 private static final MethodHandle PROTECTED_STR_CONSTR_HANDLE;
57 private static final Class<?>[] PROTECTED_STR_CONSTR_PARAM_TYPES;
58
59 static {
60 Field charsField;
61 charsField = AccessController.doPrivileged(new PrivilegedAction<Field>() {
62 @Override
63 public Field run() {
64 Field charsField;
65 try {
66 charsField = String.class.getDeclaredField("value");
67 Class<?> type = charsField.getType();
68 if (type.isArray() && type.getComponentType() == char.class) {
69 charsField.setAccessible(true);
70 } else {
71 Logger logger = Logger.getLogger(Strings.class.getName());
72 logger.warning("char array stealing from String not supported");
73 charsField = null;
74 }
75 } catch (NoSuchFieldException ex) {
76 Logger logger = Logger.getLogger(Strings.class.getName());
77 logger.warning("char array stealing from String not supported");
78 logger.log(Level.FINEST, "Exception detail", ex);
79 charsField = null;
80 }
81 return charsField;
82 }
83 });
84 MethodHandles.Lookup lookup = MethodHandles.lookup();
85 if (charsField != null && char[].class == charsField.getType()) {
86 try {
87 CHARS_FIELD_GET = lookup.unreflectGetter(charsField);
88 } catch (IllegalAccessException ex) {
89 throw new ExceptionInInitializerError(ex);
90 }
91 } else {
92 CHARS_FIELD_GET = null;
93 }
94
95
96
97 Constructor<String> prConstr = AccessController.doPrivileged(
98 new PrivilegedAction<Constructor<String>>() {
99 @Override
100 public Constructor<String> run() {
101 Constructor<String> constr;
102 try {
103 constr = String.class.getDeclaredConstructor(char[].class, boolean.class);
104 constr.setAccessible(true);
105 } catch (NoSuchMethodException ex) {
106 try {
107 constr = String.class.getDeclaredConstructor(int.class, int.class, char[].class);
108 constr.setAccessible(true);
109 } catch (NoSuchMethodException ex2) {
110 ex2.addSuppressed(ex);
111 Logger logger = Logger.getLogger(Strings.class.getName());
112 logger.log(Level.FINE, "Building String from char[] without copy not supported");
113 logger.log(Level.FINEST, "Exception detail", ex2);
114 constr = null;
115 }
116 }
117 return constr;
118 }
119 });
120
121 if (prConstr == null) {
122 PROTECTED_STR_CONSTR_PARAM_TYPES = null;
123 PROTECTED_STR_CONSTR_HANDLE = null;
124 } else {
125 PROTECTED_STR_CONSTR_PARAM_TYPES = prConstr.getParameterTypes();
126 try {
127 PROTECTED_STR_CONSTR_HANDLE = lookup.unreflectConstructor(prConstr);
128 } catch (IllegalAccessException ex) {
129 throw new ExceptionInInitializerError(ex);
130 }
131 }
132 }
133
134
135
136 private UnsafeString() { }
137
138
139
140
141
142
143
144 public static char[] steal(final String str) {
145 if (CHARS_FIELD_GET == null) {
146 return str.toCharArray();
147 } else {
148 try {
149 return (char[]) CHARS_FIELD_GET.invokeExact(str);
150 } catch (Throwable ex) {
151 UnknownError err = new UnknownError("Error while stealing String char array");
152 err.addSuppressed(ex);
153 throw err;
154 }
155 }
156 }
157
158
159
160
161
162
163
164 public static String wrap(final char[] chars) {
165 if (PROTECTED_STR_CONSTR_PARAM_TYPES != null) {
166 try {
167 if (PROTECTED_STR_CONSTR_PARAM_TYPES.length == 3) {
168 return (String) PROTECTED_STR_CONSTR_HANDLE.invokeExact(0, chars.length, chars);
169 } else {
170 return (String) PROTECTED_STR_CONSTR_HANDLE.invokeExact(chars, true);
171 }
172 } catch (Throwable ex) {
173 UnknownError err = new UnknownError("Error while wrapping String char array");
174 err.addSuppressed(ex);
175 throw err;
176 }
177 } else {
178 return new String(chars);
179 }
180 }
181
182 }