|
8 | 8 | import java.lang.reflect.InvocationTargetException;
|
9 | 9 | import java.lang.reflect.Method;
|
10 | 10 | import java.util.ArrayList;
|
| 11 | +import java.util.Arrays; |
11 | 12 | import java.util.List;
|
12 | 13 |
|
13 | 14 | /**
|
@@ -167,7 +168,7 @@ public Value newInstance(Value[] args) {
|
167 | 168 | return findConstructorAndInstantiate(args, clazz.getConstructors());
|
168 | 169 | }
|
169 | 170 |
|
170 |
| - private Value cast(Value... args) { |
| 171 | + private Value cast(Value[] args) { |
171 | 172 | Arguments.check(1, args.length);
|
172 | 173 | return objectToValue(clazz, clazz.cast(((ObjectValue)args[0]).object));
|
173 | 174 | }
|
@@ -337,7 +338,15 @@ private static boolean isMatch(Value[] args, Class<?>[] types) {
|
337 | 338 | boolean assignable = unboxed != null;
|
338 | 339 | final Object object = valueToObject(arg);
|
339 | 340 | assignable = assignable && (object != null);
|
340 |
| - assignable = assignable && (unboxed.isAssignableFrom(object.getClass())); |
| 341 | + if (assignable && unboxed.isArray() && object.getClass().isArray()) { |
| 342 | + final Class<?> uComponentType = unboxed.getComponentType(); |
| 343 | + final Class<?> oComponentType = object.getClass().getComponentType(); |
| 344 | + assignable = assignable && (uComponentType != null); |
| 345 | + assignable = assignable && (oComponentType != null); |
| 346 | + assignable = assignable && (uComponentType.isAssignableFrom(oComponentType)); |
| 347 | + } else { |
| 348 | + assignable = assignable && (unboxed.isAssignableFrom(object.getClass())); |
| 349 | + } |
341 | 350 | if (assignable) continue;
|
342 | 351 |
|
343 | 352 | return false;
|
@@ -460,7 +469,7 @@ private static Value arrayToValue(Class<?> clazz, Object o) {
|
460 | 469 | }
|
461 | 470 | return result;
|
462 | 471 | }
|
463 |
| - |
| 472 | + |
464 | 473 | private static Object[] valuesToObjects(Value[] args) {
|
465 | 474 | Object[] result = new Object[args.length];
|
466 | 475 | for (int i = 0; i < args.length; i++) {
|
@@ -490,11 +499,72 @@ private static Object valueToObject(Value value) {
|
490 | 499 |
|
491 | 500 | private static Object arrayToObject(ArrayValue value) {
|
492 | 501 | final int size = value.size();
|
493 |
| - final Object[] result = new Object[size]; |
| 502 | + final Object[] array = new Object[size]; |
| 503 | + if (size == 0) { |
| 504 | + return array; |
| 505 | + } |
| 506 | + |
| 507 | + Class<?> elementsType = null; |
494 | 508 | for (int i = 0; i < size; i++) {
|
495 |
| - result[i] = valueToObject(value.get(i)); |
| 509 | + array[i] = valueToObject(value.get(i)); |
| 510 | + if (i == 0) { |
| 511 | + elementsType = array[0].getClass(); |
| 512 | + } else { |
| 513 | + elementsType = mostCommonType(elementsType, array[i].getClass()); |
| 514 | + } |
| 515 | + } |
| 516 | + |
| 517 | + if (elementsType.equals(Object[].class)) { |
| 518 | + return array; |
| 519 | + } |
| 520 | + return typedArray(array, size, elementsType); |
| 521 | + } |
| 522 | + |
| 523 | + private static <T, U> T[] typedArray(U[] elements, int newLength, Class<?> elementsType) { |
| 524 | + @SuppressWarnings("unchecked") |
| 525 | + T[] copy = (T[]) Array.newInstance(elementsType, newLength); |
| 526 | + System.arraycopy(elements, 0, copy, 0, Math.min(elements.length, newLength)); |
| 527 | + return copy; |
| 528 | + } |
| 529 | + |
| 530 | + private static Class<?> mostCommonType(Class<?> c1, Class<?> c2) { |
| 531 | + if (c1.equals(c2)) { |
| 532 | + return c1; |
| 533 | + } else if (c1.isAssignableFrom(c2)) { |
| 534 | + return c1; |
| 535 | + } else if (c2.isAssignableFrom(c1)) { |
| 536 | + return c2; |
| 537 | + } |
| 538 | + final Class<?> s1 = c1.getSuperclass(); |
| 539 | + final Class<?> s2 = c2.getSuperclass(); |
| 540 | + if (s1 == null && s2 == null) { |
| 541 | + final List<Class<?>> upperTypes = Arrays.asList( |
| 542 | + Object.class, void.class, boolean.class, char.class, |
| 543 | + byte.class, short.class, int.class, long.class, |
| 544 | + float.class, double.class); |
| 545 | + for (Class<?> type : upperTypes) { |
| 546 | + if (c1.equals(type) && c2.equals(type)) { |
| 547 | + return s1; |
| 548 | + } |
| 549 | + } |
| 550 | + return Object.class; |
| 551 | + } else if (s1 == null || s2 == null) { |
| 552 | + if (c1.equals(c2)) { |
| 553 | + return c1; |
| 554 | + } |
| 555 | + if (c1.isInterface() && c1.isAssignableFrom(c2)) { |
| 556 | + return c1; |
| 557 | + } |
| 558 | + if (c2.isInterface() && c2.isAssignableFrom(c1)) { |
| 559 | + return c2; |
| 560 | + } |
| 561 | + } |
| 562 | + |
| 563 | + if (s1 != null) { |
| 564 | + return mostCommonType(s1, c2); |
| 565 | + } else { |
| 566 | + return mostCommonType(c1, s2); |
496 | 567 | }
|
497 |
| - return result; |
498 | 568 | }
|
499 | 569 | //</editor-fold>
|
500 | 570 | }
|
0 commit comments