1 /*
2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
128 }
129 if (type == boolean[].class) {
130 boolean[] booleanArray = (boolean[])array;
131 return booleanArray.clone();
132 }
133
134 Object[] objectArray = (Object[])array;
135 return objectArray.clone();
136 }
137
138
139 /**
140 * Implementation of dynamicProxy.toString()
141 */
142 private String toStringImpl() {
143 StringBuilder result = new StringBuilder(128);
144 result.append('@');
145 result.append(type.getName());
146 result.append('(');
147 boolean firstMember = true;
148 for (Map.Entry<String, Object> e : memberValues.entrySet()) {
149 if (firstMember)
150 firstMember = false;
151 else
152 result.append(", ");
153
154 result.append(e.getKey());
155 result.append('=');
156 result.append(memberValueToString(e.getValue()));
157 }
158 result.append(')');
159 return result.toString();
160 }
161
162 /**
163 * Translates a member value (in "dynamic proxy return form") into a string.
164 */
165 private static String memberValueToString(Object value) {
166 Class<?> type = value.getClass();
167 if (!type.isArray()) {
168 // primitive value, string, class, enum const, or annotation
169 if (type == Class.class)
170 return toSourceString((Class<?>) value);
171 else if (type == String.class)
172 return toSourceString((String) value);
173 if (type == Character.class)
174 return toSourceString((char) value);
175 else if (type == Double.class)
176 return toSourceString((double) value);
177 else if (type == Float.class)
178 return toSourceString((float) value);
179 else if (type == Long.class)
180 return toSourceString((long) value);
181 else
182 return value.toString();
183 } else {
184 Stream<String> stringStream;
185 if (type == byte[].class)
186 stringStream = convert((byte[]) value);
187 else if (type == char[].class)
188 stringStream = convert((char[]) value);
189 else if (type == double[].class)
190 stringStream = DoubleStream.of((double[]) value)
191 .mapToObj(AnnotationInvocationHandler::toSourceString);
192 else if (type == float[].class)
193 stringStream = convert((float[]) value);
194 else if (type == int[].class)
195 stringStream = IntStream.of((int[]) value).mapToObj(String::valueOf);
196 else if (type == long[].class) {
197 stringStream = LongStream.of((long[]) value)
198 .mapToObj(AnnotationInvocationHandler::toSourceString);
199 } else if (type == short[].class)
200 stringStream = convert((short[]) value);
211 else
212 stringStream = Arrays.stream((Object[])value).map(Objects::toString);
213
214 return stringStreamToString(stringStream);
215 }
216 }
217
218 /**
219 * Translates a Class value to a form suitable for use in the
220 * string representation of an annotation.
221 */
222 private static String toSourceString(Class<?> clazz) {
223 Class<?> finalComponent = clazz;
224 StringBuilder arrayBackets = new StringBuilder();
225
226 while(finalComponent.isArray()) {
227 finalComponent = finalComponent.getComponentType();
228 arrayBackets.append("[]");
229 }
230
231 return finalComponent.getName() + arrayBackets.toString() + ".class" ;
232 }
233
234 private static String toSourceString(float f) {
235 if (Float.isFinite(f))
236 return Float.toString(f) + "f" ;
237 else {
238 if (Float.isInfinite(f)) {
239 return (f < 0.0f) ? "-1.0f/0.0f": "1.0f/0.0f";
240 } else
241 return "0.0f/0.0f";
242 }
243 }
244
245 private static String toSourceString(double d) {
246 if (Double.isFinite(d))
247 return Double.toString(d);
248 else {
249 if (Double.isInfinite(d)) {
250 return (d < 0.0f) ? "-1.0/0.0": "1.0/0.0";
251 } else
252 return "0.0/0.0";
253 }
254 }
255
256 private static String toSourceString(char c) {
257 StringBuilder sb = new StringBuilder(4);
258 sb.append('\'');
259 if (c == '\'')
260 sb.append("\\'");
261 else
262 sb.append(c);
263 return sb.append('\'')
264 .toString();
265 }
266
267 private static String toSourceString(long ell) {
268 String str = String.valueOf(ell);
269 return (ell < Integer.MIN_VALUE || ell > Integer.MAX_VALUE)
270 ? (str + 'L') : str;
271 }
272
273 /**
274 * Return a string suitable for use in the string representation
275 * of an annotation.
276 */
277 private static String toSourceString(String s) {
278 StringBuilder sb = new StringBuilder();
279 sb.append('"');
280 // Escape embedded quote characters, if present, but don't do
281 // anything more heroic.
282 sb.append(s.replace("\"", "\\\""));
283 sb.append('"');
284 return sb.toString();
285 }
286
287 private static Stream<String> convert(byte[] values) {
288 List<String> list = new ArrayList<>(values.length);
289 for (byte b : values)
290 list.add(Byte.toString(b));
291 return list.stream();
292 }
293
294 private static Stream<String> convert(char[] values) {
295 List<String> list = new ArrayList<>(values.length);
296 for (char c : values)
297 list.add(toSourceString(c));
298 return list.stream();
299 }
300
301 private static Stream<String> convert(float[] values) {
302 List<String> list = new ArrayList<>(values.length);
303 for (float f : values) {
304 list.add(toSourceString(f));
305 }
306 return list.stream();
307 }
308
309 private static Stream<String> convert(short[] values) {
310 List<String> list = new ArrayList<>(values.length);
|
1 /*
2 * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
128 }
129 if (type == boolean[].class) {
130 boolean[] booleanArray = (boolean[])array;
131 return booleanArray.clone();
132 }
133
134 Object[] objectArray = (Object[])array;
135 return objectArray.clone();
136 }
137
138
139 /**
140 * Implementation of dynamicProxy.toString()
141 */
142 private String toStringImpl() {
143 StringBuilder result = new StringBuilder(128);
144 result.append('@');
145 result.append(type.getName());
146 result.append('(');
147 boolean firstMember = true;
148 Set<Map.Entry<String, Object>> entries = memberValues.entrySet();
149 boolean loneValue = entries.size() == 1;
150 for (Map.Entry<String, Object> e : entries) {
151 if (firstMember)
152 firstMember = false;
153 else
154 result.append(", ");
155
156 String key = e.getKey();
157 if (!loneValue || !"value".equals(key)) {
158 result.append(key);
159 result.append('=');
160 }
161 loneValue = false;
162 result.append(memberValueToString(e.getValue()));
163 }
164 result.append(')');
165 return result.toString();
166 }
167
168 /**
169 * Translates a member value (in "dynamic proxy return form") into a string.
170 */
171 private static String memberValueToString(Object value) {
172 Class<?> type = value.getClass();
173 if (!type.isArray()) {
174 // primitive value, string, class, enum const, or annotation
175 if (type == Class.class)
176 return toSourceString((Class<?>) value);
177 else if (type == String.class)
178 return toSourceString((String) value);
179 if (type == Character.class)
180 return toSourceString((char) value);
181 else if (type == Double.class)
182 return toSourceString((double) value);
183 else if (type == Float.class)
184 return toSourceString((float) value);
185 else if (type == Long.class)
186 return toSourceString((long) value);
187 else if (type == Byte.class)
188 return toSourceString((byte) value);
189 else
190 return value.toString();
191 } else {
192 Stream<String> stringStream;
193 if (type == byte[].class)
194 stringStream = convert((byte[]) value);
195 else if (type == char[].class)
196 stringStream = convert((char[]) value);
197 else if (type == double[].class)
198 stringStream = DoubleStream.of((double[]) value)
199 .mapToObj(AnnotationInvocationHandler::toSourceString);
200 else if (type == float[].class)
201 stringStream = convert((float[]) value);
202 else if (type == int[].class)
203 stringStream = IntStream.of((int[]) value).mapToObj(String::valueOf);
204 else if (type == long[].class) {
205 stringStream = LongStream.of((long[]) value)
206 .mapToObj(AnnotationInvocationHandler::toSourceString);
207 } else if (type == short[].class)
208 stringStream = convert((short[]) value);
219 else
220 stringStream = Arrays.stream((Object[])value).map(Objects::toString);
221
222 return stringStreamToString(stringStream);
223 }
224 }
225
226 /**
227 * Translates a Class value to a form suitable for use in the
228 * string representation of an annotation.
229 */
230 private static String toSourceString(Class<?> clazz) {
231 Class<?> finalComponent = clazz;
232 StringBuilder arrayBackets = new StringBuilder();
233
234 while(finalComponent.isArray()) {
235 finalComponent = finalComponent.getComponentType();
236 arrayBackets.append("[]");
237 }
238
239 return finalComponent.getName() + arrayBackets.toString() + ".class";
240 }
241
242 private static String toSourceString(float f) {
243 if (Float.isFinite(f))
244 return Float.toString(f) + "f" ;
245 else {
246 if (Float.isInfinite(f)) {
247 return (f < 0.0f) ? "-1.0f/0.0f": "1.0f/0.0f";
248 } else
249 return "0.0f/0.0f";
250 }
251 }
252
253 private static String toSourceString(double d) {
254 if (Double.isFinite(d))
255 return Double.toString(d);
256 else {
257 if (Double.isInfinite(d)) {
258 return (d < 0.0f) ? "-1.0/0.0": "1.0/0.0";
259 } else
260 return "0.0/0.0";
261 }
262 }
263
264 private static String toSourceString(char c) {
265 StringBuilder sb = new StringBuilder(4);
266 sb.append('\'');
267 sb.append(quote(c));
268 return sb.append('\'') .toString();
269 }
270
271 /**
272 * Escapes a character if it has an escape sequence or is
273 * non-printable ASCII. Leaves non-ASCII characters alone.
274 */
275 private static String quote(char ch) {
276 switch (ch) {
277 case '\b': return "\\b";
278 case '\f': return "\\f";
279 case '\n': return "\\n";
280 case '\r': return "\\r";
281 case '\t': return "\\t";
282 case '\'': return "\\'";
283 case '\"': return "\\\"";
284 case '\\': return "\\\\";
285 default:
286 return (isPrintableAscii(ch))
287 ? String.valueOf(ch)
288 : String.format("\\u%04x", (int) ch);
289 }
290 }
291
292 /**
293 * Is a character printable ASCII?
294 */
295 private static boolean isPrintableAscii(char ch) {
296 return ch >= ' ' && ch <= '~';
297 }
298
299 private static String toSourceString(byte b) {
300 return String.format("(byte)0x%02x", b);
301 }
302
303 private static String toSourceString(long ell) {
304 return String.valueOf(ell) + "L";
305 }
306
307 /**
308 * Return a string suitable for use in the string representation
309 * of an annotation.
310 */
311 private static String toSourceString(String s) {
312 StringBuilder sb = new StringBuilder();
313 sb.append('"');
314 for (int i = 0; i < s.length(); i++) {
315 sb.append(quote(s.charAt(i)));
316 }
317 sb.append('"');
318 return sb.toString();
319 }
320
321 private static Stream<String> convert(byte[] values) {
322 List<String> list = new ArrayList<>(values.length);
323 for (byte b : values)
324 list.add(toSourceString(b));
325 return list.stream();
326 }
327
328 private static Stream<String> convert(char[] values) {
329 List<String> list = new ArrayList<>(values.length);
330 for (char c : values)
331 list.add(toSourceString(c));
332 return list.stream();
333 }
334
335 private static Stream<String> convert(float[] values) {
336 List<String> list = new ArrayList<>(values.length);
337 for (float f : values) {
338 list.add(toSourceString(f));
339 }
340 return list.stream();
341 }
342
343 private static Stream<String> convert(short[] values) {
344 List<String> list = new ArrayList<>(values.length);
|