]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/cojen/classfile/TypeDesc.java
List the unsatisfied dependencies in CanvasContext
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / cojen / classfile / TypeDesc.java
1 /*
2  *  Copyright 2004-2010 Brian S O'Neill
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16
17 package org.cojen.classfile;
18
19 import java.io.Serializable;
20 import java.lang.ref.SoftReference;
21 import java.lang.reflect.Array;
22 import java.util.Collections;
23 import java.util.Map;
24
25 import org.cojen.util.SoftValuedHashMap;
26 import org.cojen.util.WeakCanonicalSet;
27 import org.cojen.util.WeakIdentityMap;
28
29 /**
30  * This class is used to build field and return type descriptor strings as 
31  * defined in <i>The Java Virtual Machine Specification</i>, section 4.3.2.
32  * TypeDesc instances are canonicalized and therefore "==" comparable.
33  *
34  * @author Brian S O'Neill
35  */
36 @SuppressWarnings("rawtypes")
37 public abstract class TypeDesc extends Descriptor implements Serializable {
38     /**
39      * Type code returned from getTypeCode, which can be used with the
40      * newarray instruction.
41      */
42     public final static int
43         OBJECT_CODE = 0,
44         VOID_CODE = 1,
45         BOOLEAN_CODE = 4,
46         CHAR_CODE = 5,
47         FLOAT_CODE = 6,
48         DOUBLE_CODE = 7,
49         BYTE_CODE = 8,
50         SHORT_CODE = 9,
51         INT_CODE = 10,
52         LONG_CODE = 11;
53
54     /** Primitive type void */
55     public final static TypeDesc VOID;
56     /** Primitive type boolean */
57     public final static TypeDesc BOOLEAN;
58     /** Primitive type char */
59     public final static TypeDesc CHAR;
60     /** Primitive type byte */
61     public final static TypeDesc BYTE;
62     /** Primitive type short */
63     public final static TypeDesc SHORT;
64     /** Primitive type int */
65     public final static TypeDesc INT;
66     /** Primitive type long */
67     public final static TypeDesc LONG;
68     /** Primitive type float */
69     public final static TypeDesc FLOAT;
70     /** Primitive type double */
71     public final static TypeDesc DOUBLE;
72
73     /** Object type java.lang.Object, provided for convenience */
74     public final static TypeDesc OBJECT;
75     /** Object type java.lang.String, provided for convenience */
76     public final static TypeDesc STRING;
77
78     // Pool of all shared instances. Ensures identity comparison works.
79     final static WeakCanonicalSet<Descriptor> cInstances;
80
81     // Cache that maps Classes to TypeDescs.
82     private final static Map<Class, TypeDesc> cClassesToInstances;
83
84     // Cache that maps String names to TypeDescs.
85     private final static Map<String, TypeDesc> cNamesToInstances;
86
87     // Cache that maps String descriptors to TypeDescs.
88     private final static Map<String, TypeDesc> cDescriptorsToInstances;
89
90     static {
91         cInstances = new WeakCanonicalSet<Descriptor>();
92
93         cClassesToInstances = Collections.synchronizedMap(new WeakIdentityMap<Class, TypeDesc>());
94         cNamesToInstances = Collections.synchronizedMap(new SoftValuedHashMap<String, TypeDesc>());
95         cDescriptorsToInstances = Collections.synchronizedMap
96             (new SoftValuedHashMap<String, TypeDesc>());
97
98         VOID = intern(new PrimitiveType("V", VOID_CODE));
99         BOOLEAN = intern(new PrimitiveType("Z", BOOLEAN_CODE));
100         CHAR = intern(new PrimitiveType("C", CHAR_CODE));
101         BYTE = intern(new PrimitiveType("B", BYTE_CODE));
102         SHORT = intern(new PrimitiveType("S", SHORT_CODE));
103         INT = intern(new PrimitiveType("I", INT_CODE));
104         LONG = intern(new PrimitiveType("J", LONG_CODE));
105         FLOAT = intern(new PrimitiveType("F", FLOAT_CODE));
106         DOUBLE = intern(new PrimitiveType("D", DOUBLE_CODE));
107
108         OBJECT = forClass("java.lang.Object");
109         STRING = forClass("java.lang.String");
110     }
111
112     static TypeDesc intern(TypeDesc type) {
113         return cInstances.put(type);
114     }
115
116     /**
117      * Acquire a TypeDesc from any class, including primitives and arrays.
118      */
119     public static TypeDesc forClass(final Class clazz) {
120         if (clazz == null) {
121             return null;
122         }
123
124         TypeDesc type = (TypeDesc)cClassesToInstances.get(clazz);
125
126         if (type == null || type.toClass() != clazz) {
127             if (clazz.isArray()) {
128                 type = forClass(clazz.getComponentType()).toArrayType();
129             } else if (clazz.isPrimitive()) {
130                 if (clazz == int.class) {
131                     type = INT;
132                 } else if (clazz == boolean.class) {
133                     type = BOOLEAN;
134                 } else if (clazz == char.class) {
135                     type = CHAR;
136                 } else if (clazz == byte.class) {
137                     type = BYTE;
138                 } else if (clazz == long.class) {
139                     type = LONG;
140                 } else if (clazz == float.class) {
141                     type = FLOAT;
142                 } else if (clazz == double.class) {
143                     type = DOUBLE;
144                 } else if (clazz == short.class) {
145                     type = SHORT;
146                 } else if (clazz == void.class) {
147                     type = VOID;
148                 }
149             } else {
150                 String name = clazz.getName();
151                 type = intern(new ObjectType(generateDescriptor(name), name));
152             }
153         
154             if (type.toClass() != clazz) {
155                 type = new ObjectType(type.getDescriptor(), clazz.getName());
156                 ((ObjectType) type).setClass(clazz);
157             }
158
159             synchronized (cClassesToInstances) {
160                 if (cClassesToInstances.containsKey(clazz)) {
161                     type = (TypeDesc)cClassesToInstances.get(clazz);
162                 } else {
163                     cClassesToInstances.put(clazz, type);
164                 }
165             }
166         }
167
168         return type;
169     }
170
171     /**
172      * Acquire a TypeDesc from any class name, including primitives and arrays.
173      * Primitive and array syntax matches Java declarations.
174      */
175     public static TypeDesc forClass(final String name) throws IllegalArgumentException {
176         if (name.length() < 1) {
177             throw invalidName(name);
178         }
179
180         // TODO: Support generics in name.
181
182         TypeDesc type = (TypeDesc)cNamesToInstances.get(name);
183         if (type != null) {
184             return type;
185         }
186
187         int index1 = name.lastIndexOf('[');
188         int index2 = name.lastIndexOf(']');
189         if (index2 >= 0) {
190             if (index2 + 1 != name.length() || index1 + 1 != index2) {
191                 throw invalidName(name);
192             }
193             try {
194                 type = forClass(name.substring(0, index1)).toArrayType();
195             } catch (IllegalArgumentException e) {
196                 throw invalidName(name);
197             }
198         } else if (index1 >= 0) {
199             throw invalidName(name);
200         } else {
201             setType: {
202                 switch (name.charAt(0)) {
203                 case 'v':
204                     if (name.equals("void")) {
205                         type = VOID;
206                         break setType;
207                     }
208                     break;
209                 case 'b':
210                     if (name.equals("boolean")) {
211                         type = BOOLEAN;
212                         break setType;
213                     } else if (name.equals("byte")) {
214                         type =  BYTE;
215                         break setType;
216                     }
217                     break;
218                 case 'c':
219                     if (name.equals("char")) {
220                         type = CHAR;
221                         break setType;
222                     }
223                     break;
224                 case 's':
225                     if (name.equals("short")) {
226                         type = SHORT;
227                         break setType;
228                     }
229                     break;
230                 case 'i':
231                     if (name.equals("int")) {
232                         type = INT;
233                         break setType;
234                     }
235                     break;
236                 case 'l':
237                     if (name.equals("long")) {
238                         type = LONG;
239                         break setType;
240                     }
241                     break;
242                 case 'f':
243                     if (name.equals("float")) {
244                         type = FLOAT;
245                         break setType;
246                     }
247                     break;
248                 case 'd':
249                     if (name.equals("double")) {
250                         type = DOUBLE;
251                         break setType;
252                     }
253                     break;
254                 }
255
256                 String desc = generateDescriptor(name);
257                 if (name.indexOf('/') < 0) {
258                     type = new ObjectType(desc, name);
259                 } else {
260                     type = new ObjectType(desc, name.replace('/', '.'));
261                 }
262                 type = intern(type);
263             }
264         }
265
266         cNamesToInstances.put(name, type);
267         return type;
268     }
269
270     private static IllegalArgumentException invalidName(String name) {
271         return new IllegalArgumentException("Invalid name: " + name);
272     }
273
274     /**
275      * Acquire a TypeDesc from a type descriptor. This syntax is described in
276      * section 4.3.2, Field Descriptors.
277      */
278     public static TypeDesc forDescriptor(final String desc) throws IllegalArgumentException {
279         TypeDesc type = (TypeDesc)cDescriptorsToInstances.get(desc);
280         if (type != null) {
281             return type;
282         }
283
284         // TODO: Support generics in descriptor.
285
286         String rootDesc = desc;
287         int cursor = 0;
288         int dim = 0;
289         try {
290             char c;
291             while ((c = rootDesc.charAt(cursor++)) == '[') {
292                 dim++;
293             }
294
295             switch (c) {
296             case 'V':
297                 type = VOID;
298                 break;
299             case 'Z':
300                 type = BOOLEAN;
301                 break;
302             case 'C':
303                 type = CHAR;
304                 break;
305             case 'B':
306                 type = BYTE;
307                 break;
308             case 'S':
309                 type = SHORT;
310                 break;
311             case 'I':
312                 type = INT;
313                 break;
314             case 'J':
315                 type = LONG;
316                 break;
317             case 'F':
318                 type = FLOAT;
319                 break;
320             case 'D':
321                 type = DOUBLE;
322                 break;
323             case 'L':
324                 if (dim > 0) {
325                     rootDesc = rootDesc.substring(dim);
326                     cursor = 1;
327                 }
328                 StringBuffer name = new StringBuffer(rootDesc.length() - 2);
329                 while ((c = rootDesc.charAt(cursor++)) != ';') {
330                     if (c == '/') {
331                         c = '.';
332                     }
333                     name.append(c);
334                 }
335                 type = intern(new ObjectType(rootDesc, name.toString()));
336                 break;
337             default:
338                 throw invalidDescriptor(desc);
339             }
340         } catch (NullPointerException e) {
341             throw invalidDescriptor(desc);
342         } catch (IndexOutOfBoundsException e) {
343             throw invalidDescriptor(desc);
344         }
345
346         if (cursor != rootDesc.length()) {
347             throw invalidDescriptor(desc);
348         }
349
350         while (--dim >= 0) {
351             type = type.toArrayType();
352         }
353
354         cDescriptorsToInstances.put(desc, type);
355         return type;
356     }
357
358     private static IllegalArgumentException invalidDescriptor(String desc) {
359         return new IllegalArgumentException("Invalid descriptor: " + desc);
360     }
361
362     private static String generateDescriptor(String classname) {
363         int length = classname.length();
364         char[] buf = new char[length + 2];
365         buf[0] = 'L';
366         classname.getChars(0, length, buf, 1);
367         int i;
368         for (i=1; i<=length; i++) {
369             char c = buf[i];
370             if (c == '.') {
371                 buf[i] = '/';
372             }
373         }
374         buf[i] = ';';
375         return new String(buf);
376     }
377
378     transient final String mDescriptor;
379
380     TypeDesc(String desc) {
381         mDescriptor = desc;
382     }
383
384     /**
385      * Returns a type descriptor string, excluding generics.
386      */
387     public final String getDescriptor() {
388         return mDescriptor;
389     }
390
391     /**
392      * Returns a type descriptor string, including any generics.
393      */
394     //public abstract String getGenericDescriptor();
395
396     /**
397      * Returns the class name for this descriptor. If the type is primitive,
398      * then the Java primitive type name is returned. If the type is an array,
399      * only the root component type name is returned.
400      */
401     public abstract String getRootName();
402
403     /**
404      * Returns the class name for this descriptor. If the type is primitive,
405      * then the Java primitive type name is returned. If the type is an array,
406      * "[]" is append at the end of the name for each dimension.
407      */
408     public abstract String getFullName();
409
410     // TODO
411     //public abstract String getGenericRootName();
412
413     // TODO
414     //public abstract String getGenericFullName();
415
416     /**
417      * Returns a type code for operating on primitive types in switches. If
418      * not primitive, OBJECT_CODE is returned.
419      */
420     public abstract int getTypeCode();
421
422     /**
423      * Returns true if this is a primitive type.
424      */
425     public abstract boolean isPrimitive();
426
427     /**
428      * Returns true if this is a primitive long or double type.
429      */
430     public abstract boolean isDoubleWord();
431
432     /**
433      * Returns true if this is an array type.
434      */
435     public abstract boolean isArray();
436
437     /**
438      * Returns the number of dimensions this array type has. If not an array,
439      * zero is returned.
440      */
441     public abstract int getDimensions();
442
443     /**
444      * Returns the component type of this array type. If not an array, null is
445      * returned.
446      */
447     public abstract TypeDesc getComponentType();
448
449     /**
450      * Returns the root component type of this array type. If not an array,
451      * null is returned.
452      */
453     public abstract TypeDesc getRootComponentType();
454
455     /**
456      * Convertes this type to an array type. If already an array, another
457      * dimension is added.
458      */
459     public abstract TypeDesc toArrayType();
460
461     /**
462      * Returns the object peer of this primitive type. For int, the object peer
463      * is java.lang.Integer. If this type is an object type, it is simply 
464      * returned.
465      */
466     public abstract TypeDesc toObjectType();
467
468     /**
469      * Returns the primitive peer of this object type, if one exists. For
470      * java.lang.Integer, the primitive peer is int. If this type is a
471      * primitive type, it is simply returned. Arrays have no primitive peer,
472      * and so null is returned instead.
473      */
474     public abstract TypeDesc toPrimitiveType();
475
476     /**
477      * Returns this type as a class. If the class isn't found, null is
478      * returned.
479      */
480     public abstract Class toClass();
481
482     /**
483      * Returns this type as a class. If the class isn't found, null is
484      * returned.
485      * @param loader optional ClassLoader to load class from
486      */
487     public abstract Class toClass(ClassLoader loader);
488
489     public String toString() {
490         // TODO: Return generic descriptor
491         return mDescriptor;
492     }
493
494     public int hashCode() {
495         return mDescriptor.hashCode();
496     }
497
498     public boolean equals(Object other) {
499         if (this == other) {
500             return true;
501         }
502         if (other instanceof TypeDesc) {
503             return ((TypeDesc)other).mDescriptor.equals(mDescriptor);
504         }
505         return false;
506     }
507
508     private static class PrimitiveType extends TypeDesc {
509         private transient final int mCode;
510         private transient TypeDesc mArrayType;
511         private transient TypeDesc mObjectType;
512         
513         PrimitiveType(String desc, int code) {
514             super(desc);
515             mCode = code;
516         }
517
518         public String getRootName() {
519             switch (mCode) {
520             default:
521             case VOID_CODE:
522                 return "void";
523             case BOOLEAN_CODE:
524                 return "boolean";
525             case CHAR_CODE:
526                 return "char";
527             case BYTE_CODE:
528                 return "byte";
529             case SHORT_CODE:
530                 return "short";
531             case INT_CODE:
532                 return "int";
533             case LONG_CODE:
534                 return "long";
535             case FLOAT_CODE:
536                 return "float";
537             case DOUBLE_CODE:
538                 return "double";
539             }
540         }
541         
542         public String getFullName() {
543             return getRootName();
544         }
545
546         public int getTypeCode() {
547             return mCode;
548         }
549         
550         public boolean isPrimitive() {
551             return true;
552         }
553         
554         public boolean isDoubleWord() {
555             return mCode == DOUBLE_CODE || mCode == LONG_CODE;
556         }
557         
558         public boolean isArray() {
559             return false;
560         }
561         
562         public int getDimensions() {
563             return 0;
564         }
565         
566         public TypeDesc getComponentType() {
567             return null;
568         }
569         
570         public TypeDesc getRootComponentType() {
571             return null;
572         }
573         
574         public TypeDesc toArrayType() {
575             if (mArrayType == null) {
576                 char[] buf = new char[2];
577                 buf[0] = '[';
578                 buf[1] = mDescriptor.charAt(0);
579                 mArrayType = intern(new ArrayType(new String(buf), this));
580             }
581             return mArrayType;
582         }
583         
584         public TypeDesc toObjectType() {
585             if (mObjectType == null) {
586                 switch (mCode) {
587                 default:
588                 case VOID_CODE:
589                     mObjectType = forClass("java.lang.Void");
590                     break;
591                 case BOOLEAN_CODE:
592                     mObjectType = forClass("java.lang.Boolean");
593                     break;
594                 case CHAR_CODE:
595                     mObjectType = forClass("java.lang.Character");
596                     break;
597                 case BYTE_CODE:
598                     mObjectType = forClass("java.lang.Byte");
599                     break;
600                 case SHORT_CODE:
601                     mObjectType = forClass("java.lang.Short");
602                     break;
603                 case INT_CODE:
604                     mObjectType = forClass("java.lang.Integer");
605                     break;
606                 case LONG_CODE:
607                     mObjectType = forClass("java.lang.Long");
608                     break;
609                 case FLOAT_CODE:
610                     mObjectType = forClass("java.lang.Float");
611                     break;
612                 case DOUBLE_CODE:
613                     mObjectType = forClass("java.lang.Double");
614                     break;
615                 }
616             }
617             return mObjectType;
618         }
619         
620         public TypeDesc toPrimitiveType() {
621             return this;
622         }
623
624         public Class toClass() {
625             switch (mCode) {
626             default:
627             case VOID_CODE:
628                 return void.class;
629             case BOOLEAN_CODE:
630                 return boolean.class;
631             case CHAR_CODE:
632                 return char.class;
633             case BYTE_CODE:
634                 return byte.class;
635             case SHORT_CODE:
636                 return short.class;
637             case INT_CODE:
638                 return int.class;
639             case LONG_CODE:
640                 return long.class;
641             case FLOAT_CODE:
642                 return float.class;
643             case DOUBLE_CODE:
644                 return double.class;
645             }
646         }
647
648         public Class toClass(ClassLoader loader) {
649             return toClass();
650         }
651     }
652
653     private static class ObjectType extends TypeDesc {
654         private transient final String mName;
655         private transient TypeDesc mArrayType;
656         private transient TypeDesc mPrimitiveType;
657
658         // Since cClassesToInstances may reference this instance, softly
659         // reference back to class to allow it to be garbage collected.
660         private transient SoftReference<Class> mClassRef;
661
662         ObjectType(String desc, String name) {
663             super(desc);
664             mName = name;
665         }
666
667         public String getRootName() {
668             return mName;
669         }
670
671         public String getFullName() {
672             return mName;
673         }
674
675         public int getTypeCode() {
676             return OBJECT_CODE;
677         }
678
679         public boolean isPrimitive() {
680             return false;
681         }
682         
683         public boolean isDoubleWord() {
684             return false;
685         }
686         
687         public boolean isArray() {
688             return false;
689         }
690         
691         public int getDimensions() {
692             return 0;
693         }
694         
695         public TypeDesc getComponentType() {
696             return null;
697         }
698         
699         public TypeDesc getRootComponentType() {
700             return null;
701         }
702         
703         public TypeDesc toArrayType() {
704             if (mArrayType == null) {
705                 int length = mDescriptor.length();
706                 char[] buf = new char[length + 1];
707                 buf[0] = '[';
708                 mDescriptor.getChars(0, length, buf, 1);
709                 mArrayType = intern(new ArrayType(new String(buf), this));
710             }
711             return mArrayType;
712         }
713         
714         public TypeDesc toObjectType() {
715             return this;
716         }
717         
718         public TypeDesc toPrimitiveType() {
719             if (mPrimitiveType == null) {
720                 String name = mName;
721                 if (name.startsWith("java.lang.") && name.length() > 10) {
722                     switch (name.charAt(10)) {
723                     case 'V':
724                         if (name.equals("java.lang.Void")) {
725                             mPrimitiveType = VOID;
726                         }
727                         break;
728                     case 'B':
729                         if (name.equals("java.lang.Boolean")) {
730                             mPrimitiveType = BOOLEAN;
731                         } else if (name.equals("java.lang.Byte")) {
732                             mPrimitiveType = BYTE;
733                         }
734                         break;
735                     case 'C':
736                         if (name.equals("java.lang.Character")) {
737                             mPrimitiveType = CHAR;
738                         }
739                         break;
740                     case 'S':
741                         if (name.equals("java.lang.Short")) {
742                             mPrimitiveType = SHORT;
743                         }
744                         break;
745                     case 'I':
746                         if (name.equals("java.lang.Integer")) {
747                             mPrimitiveType = INT;
748                         }
749                         break;
750                     case 'L':
751                         if (name.equals("java.lang.Long")) {
752                             mPrimitiveType = LONG;
753                         }
754                         break;
755                     case 'F':
756                         if (name.equals("java.lang.Float")) {
757                             mPrimitiveType = FLOAT;
758                         }
759                         break;
760                     case 'D':
761                         if (name.equals("java.lang.Double")) {
762                             mPrimitiveType = DOUBLE;
763                         }
764                         break;
765                     }
766                 }
767             }
768
769             return mPrimitiveType;
770         }
771
772         public final synchronized Class toClass() {
773             Class clazz;
774             if (mClassRef != null) {
775                 clazz = mClassRef.get();
776                 if (clazz != null) {
777                     return clazz;
778                 }
779             }
780             clazz = toClass(null);
781             mClassRef = new SoftReference<Class>(clazz);
782             return clazz;
783         }
784
785         public Class toClass(ClassLoader loader) {
786             TypeDesc type = toPrimitiveType();
787             if (type != null) {
788                 switch (type.getTypeCode()) {
789                 default:
790                 case VOID_CODE:
791                     return Void.class;
792                 case BOOLEAN_CODE:
793                     return Boolean.class;
794                 case CHAR_CODE:
795                     return Character.class;
796                 case FLOAT_CODE:
797                     return Float.class;
798                 case DOUBLE_CODE:
799                     return Double.class;
800                 case BYTE_CODE:
801                     return Byte.class;
802                 case SHORT_CODE:
803                     return Short.class;
804                 case INT_CODE:
805                     return Integer.class;
806                 case LONG_CODE:
807                     return Long.class;
808                 }
809             }
810
811             try {
812                 if (loader == null) {
813                     return Class.forName(mName);
814                 } else {
815                     return loader.loadClass(mName);
816                 }
817             } catch (ClassNotFoundException e) {
818                 return null;
819             }
820         }
821
822         void setClass(Class clazz) {
823             mClassRef = new SoftReference<Class>(clazz);
824         }
825     }
826
827     private static class ArrayType extends ObjectType {
828         private transient final TypeDesc mComponent;
829         private transient final String mFullName;
830
831         ArrayType(String desc, TypeDesc component) {
832             super(desc, component.getRootName());
833             mComponent = component;
834             mFullName = component.getFullName().concat("[]");
835         }
836
837         public String getFullName() {
838             return mFullName;
839         }
840
841         public boolean isArray() {
842             return true;
843         }
844         
845         public int getDimensions() {
846             return mComponent.getDimensions() + 1;
847         }
848         
849         public TypeDesc getComponentType() {
850             return mComponent;
851         }
852         
853         public TypeDesc getRootComponentType() {
854             TypeDesc type = mComponent;
855             while (type.isArray()) {
856                 type = type.getComponentType();
857             }
858             return type;
859         }
860         
861         public TypeDesc toPrimitiveType() {
862             return null;
863         }
864
865         public Class toClass(ClassLoader loader) {
866             if (loader == null) {
867                 return arrayClass(getRootComponentType().toClass());
868             } else {
869                 return arrayClass(getRootComponentType().toClass(loader));
870             }
871         }
872
873         private Class arrayClass(Class clazz) {
874             if (clazz == null) {
875                 return null;
876             }
877             int dim = getDimensions();
878             try {
879                 if (dim == 1) {
880                     return Array.newInstance(clazz, 0).getClass();
881                 } else {
882                     return Array.newInstance(clazz, new int[dim]).getClass();
883                 }
884             } catch (IllegalArgumentException e) {
885                 return null;
886             }
887         }
888     }
889 }