T invoke(ANY object, String methodName, V... args) {
39 | return console.invoke(object, methodName, args);
40 | }
41 |
42 | /**
43 | * Returns the index of the first method with the specified name.
44 | */
45 | public int getIndex(String methodName) {
46 | return console.indexOfMethod(methodName);
47 | }
48 |
49 | public int getIndex(Method method) {
50 | return console.indexOfMethod(method);
51 | }
52 |
53 | /**
54 | * Returns the index of the first method with the specified name and param types.
55 | */
56 | public int getIndex(String methodName, Class... paramTypes) {
57 | return console.indexOfMethod(null, methodName, paramTypes);
58 | }
59 |
60 | /**
61 | * Returns the index of the first method with the specified name and the specified number of arguments.
62 | */
63 | public int getIndex(String methodName, int paramsCount) {
64 | return console.indexOfMethod(methodName, paramsCount);
65 | }
66 |
67 | public String[] getMethodNames() {
68 | return classInfo.methodNames;
69 | }
70 |
71 | public Class[][] getParameterTypes() {
72 | return classInfo.methodParamTypes;
73 | }
74 |
75 | public Class[] getReturnTypes() {
76 | return classInfo.returnTypes;
77 | }
78 |
79 | public Integer[] getModifiers() {
80 | return classInfo.constructorModifiers;
81 | }
82 |
83 | public int getMethodCount() {
84 | return classInfo.methodCount;
85 | }
86 | }
--------------------------------------------------------------------------------
/src/com/esotericsoftware/reflectasm/util/NumberUtils.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.reflectasm.util;
2 |
3 | /*
4 | * Copyright 2002-2016 the original author or authors.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | import java.lang.reflect.Array;
20 | import java.math.BigDecimal;
21 | import java.math.BigInteger;
22 | import java.util.*;
23 |
24 | /**
25 | * Miscellaneous utility methods for number conversion and parsing.
26 | * Mainly for internal use within the framework; consider Apache's
27 | * Commons Lang for a more comprehensive suite of number utilities.
28 | *
29 | * @author Juergen Hoeller
30 | * @author Rob Harrop
31 | * @since 1.1.2
32 | */
33 | public abstract class NumberUtils {
34 | /**
35 | * Standard number types (all immutable):
36 | * Byte, Short, Integer, Long, BigInteger, Float, Double, BigDecimal.
37 | */
38 | public static final Set> STANDARD_NUMBER_TYPES;
39 | public static final Map> namePrimitiveMap = new HashMap<>();
40 | private static final BigInteger LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE);
41 | private static final BigInteger LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);
42 |
43 | static {
44 | namePrimitiveMap.put("boolean", Boolean.class);
45 | namePrimitiveMap.put("byte", Byte.class);
46 | namePrimitiveMap.put("char", Character.class);
47 | namePrimitiveMap.put("short", Short.class);
48 | namePrimitiveMap.put("int", Integer.class);
49 | namePrimitiveMap.put("long", Long.class);
50 | namePrimitiveMap.put("double", Double.class);
51 | namePrimitiveMap.put("float", Float.class);
52 | namePrimitiveMap.put("void", Void.class);
53 |
54 | Set> numberTypes = new HashSet<>(8);
55 | numberTypes.add(Byte.class);
56 | numberTypes.add(Byte.TYPE);
57 | numberTypes.add(Short.class);
58 | numberTypes.add(Short.TYPE);
59 | numberTypes.add(Integer.class);
60 | numberTypes.add(Integer.TYPE);
61 | numberTypes.add(Long.class);
62 | numberTypes.add(Long.TYPE);
63 | numberTypes.add(BigInteger.class);
64 | numberTypes.add(Float.class);
65 | numberTypes.add(Float.TYPE);
66 | numberTypes.add(Double.class);
67 | numberTypes.add(Double.TYPE);
68 | numberTypes.add(BigDecimal.class);
69 | STANDARD_NUMBER_TYPES = Collections.unmodifiableSet(numberTypes);
70 | }
71 |
72 | private static T convertOrGetDistance(V from, Class toClass, final boolean isGetDistance) {
73 | //return (T) (isGetDistance ? Integer.valueOf(5) : from);
74 | if (toClass == null) return (T) (isGetDistance ? 5 : null);
75 | if (from == null) return (T) (isGetDistance ? (toClass.isPrimitive() ? -1 : 5) : null);
76 | Class clz;
77 | boolean isClass = false;
78 |
79 | if (!(from instanceof Class)) clz = from.getClass();
80 | else {
81 | clz = (Class) from;
82 | isClass = true;
83 | }
84 |
85 | if (clz == String.class && toClass == byte[].class)
86 | return (T) (isGetDistance ? 5 : isClass ? toClass : ((String) from).getBytes());
87 |
88 | if (clz == byte[].class && toClass == String.class)
89 | return (T) (isGetDistance ? 5 : isClass ? toClass : new String((byte[]) from));
90 |
91 | if (clz == toClass || toClass.isAssignableFrom(clz)) return (T) (isGetDistance ? 5 : from);
92 | if (toClass.isArray() && clz.isArray()) {
93 | int distance = 5;
94 | toClass = toClass.getComponentType();
95 | if (isClass) return convertOrGetDistance(clz.getComponentType(), toClass, isGetDistance);
96 | Object objects = isGetDistance ? null : Array.newInstance(toClass, Array.getLength(from));
97 | for (int i = 0; i < Array.getLength(from); i++) {
98 | if (isGetDistance)
99 | distance = Math.min(distance, (int) convertOrGetDistance(Array.get(from, i), toClass, true));
100 | else Array.set(objects, i, convertOrGetDistance(Array.get(from, i), toClass, false));
101 | }
102 | return (T) (isGetDistance ? distance : objects);
103 | }
104 | if (toClass == String.class) return (T) (isGetDistance ? 2 : isClass ? toClass : String.valueOf(from));
105 | if (STANDARD_NUMBER_TYPES.contains(toClass)) {
106 | Class extends Number> to = (Class extends Number>) toClass;
107 | if (STANDARD_NUMBER_TYPES.contains(clz)) {
108 | return (T) (isGetDistance ? 4 : isClass ? toClass : convertNumberToTargetClass((Number) from, to));
109 | }
110 | if (clz == String.class) return (T) (isGetDistance ? 1 : isClass ? clz : parseNumber((String) from, to));
111 | if (clz == Character.class || clz == char.class)
112 | return (T) (isGetDistance ? 3 : isClass ? toClass : convertNumberToTargetClass((int) ((Character) from).charValue(), to));
113 | }
114 | if ((toClass == Character.class || toClass == char.class)) {
115 | if (STANDARD_NUMBER_TYPES.contains(clz))
116 | return (T) (isGetDistance ? 3 : isClass ? toClass : Character.valueOf((char) ((Number) from).intValue()));
117 | if (clz == String.class) {
118 | if (isClass) return (T) (isGetDistance ? 3 : isClass ? clz : toClass);
119 | if (((String) from).length() == 1)
120 | return (T) (isGetDistance ? 3 : isClass ? toClass : ((String) from).charAt(0));
121 | }
122 | }
123 | if (namePrimitiveMap.containsKey(toClass.getName()) && namePrimitiveMap.get(toClass.getName()) == clz) {
124 | return (T) (isGetDistance ? 5 : isClass ? toClass : from);
125 | }
126 | if (namePrimitiveMap.containsKey(clz.getName()) && namePrimitiveMap.get(clz.getName()) == toClass) {
127 | return (T) (isGetDistance ? 5 : isClass ? toClass : from);
128 | }
129 | return (T) (isGetDistance ? 0 : isClass ? clz : toClass.cast(from));
130 | }
131 |
132 | public static T convert(V from, Class toClass) {
133 | return convertOrGetDistance(from, toClass, false);
134 | }
135 |
136 | public static int getDistance(V from, Class> toClass) {
137 | return (Integer) convertOrGetDistance(from, toClass, true);
138 | }
139 |
140 | /**
141 | * Convert the given number into an instance of the given target class.
142 | *
143 | * @param number the number to convert
144 | * @param targetClass the target class to convert to
145 | * @return the converted number
146 | * @throws IllegalArgumentException if the target class is not supported
147 | * (i.e. not a standard Number subclass as included in the JDK)
148 | * @see Byte
149 | * @see Short
150 | * @see Integer
151 | * @see Long
152 | * @see BigInteger
153 | * @see Float
154 | * @see Double
155 | * @see BigDecimal
156 | */
157 | @SuppressWarnings("unchecked")
158 | public static T convertNumberToTargetClass(Number number, Class targetClass) throws IllegalArgumentException {
159 | if (number == null) return null;
160 | Number to = null;
161 | if (targetClass.isInstance(number)) {
162 | return (T) number;
163 | }
164 | Class clz = targetClass;
165 | if (clz.isPrimitive() && STANDARD_NUMBER_TYPES.contains(clz)) clz = namePrimitiveMap.get(clz.getName());
166 | if (Byte.class == clz) {
167 | long value = checkedLongValue(number, clz);
168 | if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
169 | raiseOverflowException(number, clz);
170 | }
171 | to = Byte.valueOf(number.byteValue());
172 | } else if (Short.class == clz) {
173 | long value = checkedLongValue(number, clz);
174 | if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
175 | raiseOverflowException(number, clz);
176 | }
177 | to = Short.valueOf(number.shortValue());
178 | } else if (Integer.class == clz) {
179 | long value = checkedLongValue(number, clz);
180 | if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
181 | raiseOverflowException(number, clz);
182 | }
183 | to = Integer.valueOf(number.intValue());
184 | } else if (Long.class == clz) {
185 | long value = checkedLongValue(number, clz);
186 | to = Long.valueOf(value);
187 | } else if (BigInteger.class == clz) {
188 | if (number instanceof BigDecimal) {
189 | // do not lose precision - use BigDecimal's own conversion
190 | to = ((BigDecimal) number).toBigInteger();
191 | } else {
192 | // original value is not a Big* number - use standard long conversion
193 | to = BigInteger.valueOf(number.longValue());
194 | }
195 | } else if (Float.class == clz) {
196 | to = Float.valueOf(number.floatValue());
197 | } else if (Double.class == clz) {
198 | to = Double.valueOf(number.doubleValue());
199 | } else if (BigDecimal.class == clz) {
200 | // always use BigDecimal(String) here to avoid unpredictability of BigDecimal(double)
201 | // (see BigDecimal javadoc for details)
202 | to = new BigDecimal(number.toString());
203 | }
204 | if (to == null) {
205 | throw new IllegalArgumentException("Could not convert number [" + number + "] of type [" + number.getClass().getName() + "] to unsupported target class [" + clz.getName() + "]");
206 | }
207 | return (T) to;
208 | }
209 |
210 | /**
211 | * Check for a {@code BigInteger}/{@code BigDecimal} long overflow
212 | * before returning the given number as a long value.
213 | *
214 | * @param number the number to convert
215 | * @param targetClass the target class to convert to
216 | * @return the long value, if convertible without overflow
217 | * @throws IllegalArgumentException if there is an overflow
218 | * @see #raiseOverflowException
219 | */
220 | private static long checkedLongValue(Number number, Class extends Number> targetClass) {
221 | BigInteger bigInt = null;
222 | if (number instanceof BigInteger) {
223 | bigInt = (BigInteger) number;
224 | } else if (number instanceof BigDecimal) {
225 | bigInt = ((BigDecimal) number).toBigInteger();
226 | }
227 | // Effectively analogous to JDK 8's BigInteger.longValueExact()
228 | if (bigInt != null && (bigInt.compareTo(LONG_MIN) < 0 || bigInt.compareTo(LONG_MAX) > 0)) {
229 | raiseOverflowException(number, targetClass);
230 | }
231 | return number.longValue();
232 | }
233 |
234 | /**
235 | * Raise an overflow exception for the given number and target class.
236 | *
237 | * @param number the number we tried to convert
238 | * @param targetClass the target class we tried to convert to
239 | * @throws IllegalArgumentException if there is an overflow
240 | */
241 | private static void raiseOverflowException(Number number, Class> targetClass) {
242 | throw new IllegalArgumentException("Could not convert number [" + number + "] of type [" + number.getClass().getName() + "] to target class [" + targetClass.getName() + "]: overflow");
243 | }
244 |
245 | /**
246 | * Parse the given {@code text} into a {@link Number} instance of the given
247 | * target class, using the corresponding {@code decode} / {@code valueOf} method.
248 | * Trims the input {@code String} before attempting to parse the number.
249 | *
Supports numbers in hex format (with leading "0x", "0X", or "#") as well.
250 | *
251 | * @param text the text to convert
252 | * @param targetClass the target class to parse into
253 | * @return the parsed number
254 | * @throws IllegalArgumentException if the target class is not supported
255 | * (i.e. not a standard Number subclass as included in the JDK)
256 | * @see Byte#decode
257 | * @see Short#decode
258 | * @see Integer#decode
259 | * @see Long#decode
260 | * @see #decodeBigInteger(String)
261 | * @see Float#valueOf
262 | * @see Double#valueOf
263 | * @see BigDecimal#BigDecimal(String)
264 | */
265 | @SuppressWarnings("unchecked")
266 | public static T parseNumber(String text, Class targetClass) {
267 | if (text == null) return null;
268 | String trimmed = text.replace(" ", "");
269 | if (trimmed.equals("")) return null;
270 | Class clz = targetClass;
271 | if (clz.isPrimitive()) clz = namePrimitiveMap.get(clz.getName());
272 | if (Byte.class == clz) {
273 | return (T) (isHexNumber(trimmed) ? Byte.decode(trimmed) : Byte.valueOf(trimmed));
274 | } else if (Short.class == clz) {
275 | return (T) (isHexNumber(trimmed) ? Short.decode(trimmed) : Short.valueOf(trimmed));
276 | } else if (Integer.class == clz) {
277 | return (T) (isHexNumber(trimmed) ? Integer.decode(trimmed) : Integer.valueOf(trimmed));
278 | } else if (Long.class == clz) {
279 | return (T) (isHexNumber(trimmed) ? Long.decode(trimmed) : Long.valueOf(trimmed));
280 | } else if (BigInteger.class == clz) {
281 | return (T) (isHexNumber(trimmed) ? decodeBigInteger(trimmed) : new BigInteger(trimmed));
282 | } else if (Float.class == clz) {
283 | return (T) Float.valueOf(trimmed);
284 | } else if (Double.class == clz) {
285 | return (T) Double.valueOf(trimmed);
286 | } else if (BigDecimal.class == clz || Number.class == clz) {
287 | return (T) new BigDecimal(trimmed);
288 | } else {
289 | throw new IllegalArgumentException("Cannot convert String [" + text + "] to target class [" + clz.getName() + "]");
290 | }
291 | }
292 |
293 | /**
294 | * Determine whether the given {@code value} String indicates a hex number,
295 | * i.e. needs to be passed into {@code Integer.decode} instead of
296 | * {@code Integer.valueOf}, etc.
297 | */
298 | private static boolean isHexNumber(String value) {
299 | int index = (value.startsWith("-") ? 1 : 0);
300 | return (value.startsWith("0x", index) || value.startsWith("0X", index) || value.startsWith("#", index));
301 | }
302 |
303 | /**
304 | * Decode a {@link BigInteger} from the supplied {@link String} value.
305 | * Supports decimal, hex, and octal notation.
306 | *
307 | * @see BigInteger#BigInteger(String, int)
308 | */
309 | private static BigInteger decodeBigInteger(String value) {
310 | int radix = 10;
311 | int index = 0;
312 | boolean negative = false;
313 |
314 | // Handle minus sign, if present.
315 | if (value.startsWith("-")) {
316 | negative = true;
317 | index++;
318 | }
319 |
320 | // Handle radix specifier, if present.
321 | if (value.startsWith("0x", index) || value.startsWith("0X", index)) {
322 | index += 2;
323 | radix = 16;
324 | } else if (value.startsWith("#", index)) {
325 | index++;
326 | radix = 16;
327 | } else if (value.startsWith("0", index) && value.length() > 1 + index) {
328 | index++;
329 | radix = 8;
330 | }
331 |
332 | BigInteger result = new BigInteger(value.substring(index), radix);
333 | return (negative ? result.negate() : result);
334 | }
335 | }
--------------------------------------------------------------------------------
/src/com/esotericsoftware/reflectasm/util/Probe.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.reflectasm.util;
2 |
3 | import java.util.*;
4 | import java.util.concurrent.locks.ReentrantLock;
5 |
6 | public class Probe {
7 | public static Probe p = new Probe();
8 | static Comparator