1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package com.sun.star.lib.uno.typedesc;
25 
26 import com.sun.star.lib.uno.typeinfo.AttributeTypeInfo;
27 import com.sun.star.lib.uno.typeinfo.MemberTypeInfo;
28 import com.sun.star.lib.uno.typeinfo.MethodTypeInfo;
29 import com.sun.star.lib.uno.typeinfo.ParameterTypeInfo;
30 import com.sun.star.lib.uno.typeinfo.TypeInfo;
31 import com.sun.star.uno.IFieldDescription;
32 import com.sun.star.uno.IMethodDescription;
33 import com.sun.star.uno.ITypeDescription;
34 import com.sun.star.uno.Type;
35 import com.sun.star.uno.TypeClass;
36 import java.lang.ref.ReferenceQueue;
37 import java.lang.ref.SoftReference;
38 import java.lang.reflect.Field;
39 import java.lang.reflect.Method;
40 import java.util.ArrayList;
41 import java.util.HashMap;
42 
43 /**
44  * Supplies information about UNO types.
45  *
46  * @since UDK2.0
47  */
48 public final class TypeDescription implements ITypeDescription {
getTypeDescription(String typeName)49     public static TypeDescription getTypeDescription(String typeName)
50         throws ClassNotFoundException
51     {
52         Type t = new Type(typeName);
53         if (t.getTypeClass() == TypeClass.UNKNOWN) {
54             if (typeName.startsWith("[]")) {
55                 t = new Type(typeName, TypeClass.SEQUENCE);
56             } else {
57                 t = new Type(Class.forName(typeName));
58             }
59         }
60         return get(t);
61     }
62 
getTypeDescription(Class zClass)63     public static TypeDescription getTypeDescription(Class zClass) {
64         return getDefinitely(new Type(zClass));
65     }
66 
getTypeDescription(Type type)67     public static TypeDescription getTypeDescription(Type type)
68         throws ClassNotFoundException
69     {
70         //TODO: synchronize on type?
71         TypeDescription desc = (TypeDescription) type.getTypeDescription();
72         if (desc == null) {
73             desc = getTypeDescription(type.getTypeName());
74             type.setTypeDescription(desc);
75         }
76         return desc;
77     }
78 
getTypeDescription(TypeClass typeClass)79     public static TypeDescription getTypeDescription(TypeClass typeClass) {
80         switch (typeClass.getValue()) {
81         case TypeClass.VOID_value:
82             return getDefinitely(Type.VOID);
83 
84         case TypeClass.BOOLEAN_value:
85             return getDefinitely(Type.BOOLEAN);
86 
87         case TypeClass.BYTE_value:
88             return getDefinitely(Type.BYTE);
89 
90         case TypeClass.SHORT_value:
91             return getDefinitely(Type.SHORT);
92 
93         case TypeClass.UNSIGNED_SHORT_value:
94             return getDefinitely(Type.UNSIGNED_SHORT);
95 
96         case TypeClass.LONG_value:
97             return getDefinitely(Type.LONG);
98 
99         case TypeClass.UNSIGNED_LONG_value:
100             return getDefinitely(Type.UNSIGNED_LONG);
101 
102         case TypeClass.HYPER_value:
103             return getDefinitely(Type.HYPER);
104 
105         case TypeClass.UNSIGNED_HYPER_value:
106             return getDefinitely(Type.UNSIGNED_HYPER);
107 
108         case TypeClass.FLOAT_value:
109             return getDefinitely(Type.FLOAT);
110 
111         case TypeClass.DOUBLE_value:
112             return getDefinitely(Type.DOUBLE);
113 
114         case TypeClass.CHAR_value:
115             return getDefinitely(Type.CHAR);
116 
117         case TypeClass.STRING_value:
118             return getDefinitely(Type.STRING);
119 
120         case TypeClass.TYPE_value:
121             return getDefinitely(Type.TYPE);
122 
123         case TypeClass.ANY_value:
124             return getDefinitely(Type.ANY);
125 
126         default:
127             return null;
128         }
129     }
130 
isTypeClassSimple(TypeClass typeClass)131     public static boolean isTypeClassSimple(TypeClass typeClass) {
132         return getTypeDescription(typeClass) != null;
133     }
134 
135     // @see ITypeDescription#getSuperType
getSuperType()136     public ITypeDescription getSuperType() {
137         // Arbitrarily take the first super type:
138         return superTypes == null || superTypes.length == 0
139             ? null : superTypes[0];
140     }
141 
142     // @see ITypeDescription#getMethodDescriptions
getMethodDescriptions()143     public IMethodDescription[] getMethodDescriptions() {
144         initMethodDescriptions();
145         return methodDescriptions; //TODO: clone?
146     }
147 
148     // @see ITypeDescription#getMethodDescription(int)
getMethodDescription(int methodId)149     public IMethodDescription getMethodDescription(int methodId) {
150         initMethodDescriptions();
151         return methodId < 0
152             ? null
153             : methodId < superMethodDescriptions.length
154             ? superMethodDescriptions[methodId]
155             : (methodId - superMethodDescriptions.length
156                < methodDescriptions.length)
157             ? methodDescriptions[methodId - superMethodDescriptions.length]
158             : null;
159     }
160 
161     // @see ITypeDescription#getMethodDescription(String)
getMethodDescription(String name)162     public IMethodDescription getMethodDescription(String name) {
163         initMethodDescriptions();
164         for (int i = 0; i < superMethodDescriptions.length; ++i) {
165             if (superMethodDescriptions[i].getName().equals(name)) {
166                 return superMethodDescriptions[i];
167             }
168         }
169         for (int i = 0; i < methodDescriptions.length; ++i) {
170             if (methodDescriptions[i].getName().equals(name)) {
171                 return methodDescriptions[i];
172             }
173         }
174         return null;
175     }
176 
177     // @see ITypeDescription#getFieldDescriptions
getFieldDescriptions()178     public IFieldDescription[] getFieldDescriptions() {
179         return fieldDescriptions; //TODO: clone?
180     }
181 
182     // @see ITypeDescription#getFieldDescription
getFieldDescription(String name)183     public IFieldDescription getFieldDescription(String name) {
184         for (int i = 0; i < fieldDescriptions.length; ++i) {
185             if (fieldDescriptions[i].getName().equals(name)) {
186                 return fieldDescriptions[i];
187             }
188         }
189         return superTypes != null && superTypes.length == 1
190             ? superTypes[0].getFieldDescription(name) : null;
191     }
192 
193     // @see ITypeDescription#getTypeClass
getTypeClass()194     public TypeClass getTypeClass() {
195         return typeClass;
196     }
197 
198     // @see ITypeDescription#getComponentType
getComponentType()199     public ITypeDescription getComponentType() {
200         return componentType;
201     }
202 
203     // @see ITypeDescription#getTypeName
getTypeName()204     public String getTypeName() {
205         return typeName;
206     }
207 
208     // @see ITypeDescription#getArrayTypeName
getArrayTypeName()209     public String getArrayTypeName() {
210         return arrayTypeName;
211     }
212 
213     // @see ITypeDescription#getZClass
getZClass()214     public Class getZClass() {
215         return zClass;
216     }
217 
hasTypeArguments()218     public boolean hasTypeArguments() {
219         return hasTypeArguments;
220     }
221 
222     // @see Object#toString
toString()223     public String toString() {
224         return "[" + getClass().getName() + ": " + getTypeClass() + ", "
225             + getTypeName() + "]";
226     }
227 
getDefinitely(Type type)228     private static TypeDescription getDefinitely(Type type) {
229         try {
230             return get(type);
231         } catch (ClassNotFoundException e) {
232             throw new IllegalArgumentException("this cannot happen: " + e);
233         }
234     }
235 
get(Type type)236     private static TypeDescription get(Type type) throws ClassNotFoundException
237     {
238         String typeName = type.getTypeName();
239         TypeDescription desc = cache.get(typeName);
240         if (desc == null) {
241             desc = create(type);
242             cache.put(desc);
243         }
244         return desc;
245     }
246 
create(Type type)247     private static TypeDescription create(Type type)
248         throws ClassNotFoundException
249     {
250         TypeClass typeClass = type.getTypeClass();
251         String typeName = type.getTypeName();
252         Class zClass = type.getZClass();
253         if (zClass == null) {
254             throw new ClassNotFoundException("UNO type " + type);
255         }
256         switch (typeClass.getValue()) {
257         case TypeClass.VOID_value:
258             return new TypeDescription(
259                 typeClass, typeName, "[Ljava.lang.Void;", zClass, null, null);
260 
261         case TypeClass.BOOLEAN_value:
262             return new TypeDescription(
263                 typeClass, typeName, "[Z", zClass, null, null);
264 
265         case TypeClass.BYTE_value:
266             return new TypeDescription(
267                 typeClass, typeName, "[B", zClass, null, null);
268 
269         case TypeClass.SHORT_value:
270         case TypeClass.UNSIGNED_SHORT_value:
271             return new TypeDescription(
272                 typeClass, typeName, "[S", zClass, null, null);
273 
274         case TypeClass.LONG_value:
275         case TypeClass.UNSIGNED_LONG_value:
276             return new TypeDescription(
277                 typeClass, typeName, "[I", zClass, null, null);
278 
279         case TypeClass.HYPER_value:
280         case TypeClass.UNSIGNED_HYPER_value:
281             return new TypeDescription(
282                 typeClass, typeName, "[J", zClass, null, null);
283 
284         case TypeClass.FLOAT_value:
285             return new TypeDescription(
286                 typeClass, typeName, "[F", zClass, null, null);
287 
288         case TypeClass.DOUBLE_value:
289             return new TypeDescription(
290                 typeClass, typeName, "[D", zClass, null, null);
291 
292         case TypeClass.CHAR_value:
293             return new TypeDescription(
294                 typeClass, typeName, "[C", zClass, null, null);
295 
296         case TypeClass.STRING_value:
297             return new TypeDescription(
298                 typeClass, typeName, "[Ljava.lang.String;", zClass, null, null);
299 
300         case TypeClass.TYPE_value:
301             return new TypeDescription(
302                 typeClass, typeName, "[Lcom.sun.star.uno.Type;", zClass, null,
303                 null);
304 
305         case TypeClass.ANY_value:
306             return new TypeDescription(
307                 typeClass, typeName, "[Ljava.lang.Object;", zClass, null, null);
308 
309         case TypeClass.SEQUENCE_value:
310             {
311                 // assert typeName.startsWith("[]");
312                 ITypeDescription componentType = getTypeDescription(
313                     typeName.substring("[]".length()));
314                 // assert zClass.getName().startsWith("[");
315                 return new TypeDescription(
316                     typeClass, typeName, "[" + zClass.getName(), zClass, null,
317                     componentType);
318             }
319 
320         case TypeClass.ENUM_value:
321             // assert !zClass.getName().startsWith("[");
322             return new TypeDescription(
323                 typeClass, typeName, "[L" + zClass.getName() + ";", zClass,
324                 null, null);
325 
326         case TypeClass.STRUCT_value:
327             {
328                 // This code exploits the fact that an instantiated polymorphic
329                 // struct type may not be the direct base of a struct type:
330                 Class superClass = zClass.getSuperclass();
331                 TypeDescription[] superTypes = superClass != Object.class
332                     ? new TypeDescription[] { get(new Type(superClass)) }
333                     : null;
334                 // assert !zClass.getName().startsWith("[");
335                 return new TypeDescription(
336                     typeClass, typeName, "[L" + zClass.getName() + ";", zClass,
337                     superTypes, null);
338             }
339 
340         case TypeClass.EXCEPTION_value:
341             {
342                 TypeDescription[] superTypes
343                     = typeName.equals("com.sun.star.uno.Exception")
344                     || typeName.equals("com.sun.star.uno.RuntimeException")
345                     ? null
346                     : new TypeDescription[] {
347                             get(new Type(zClass.getSuperclass())) };
348                 // assert !zClass.getName().startsWith("[");
349                 return new TypeDescription(
350                     typeClass, typeName, "[L" + zClass.getName() + ";", zClass,
351                     superTypes, null);
352             }
353 
354         case TypeClass.INTERFACE_value:
355             {
356                 List superTypes = new List();
357                 Class[] interfaces = zClass.getInterfaces();
358                 for (int i = 0; i < interfaces.length; ++i) {
359                     Type t = new Type(interfaces[i]);
360                     if (t.getTypeClass() == TypeClass.INTERFACE) {
361                         TypeDescription desc = getDefinitely(t);
362                         TypeDescription[] descs = desc.superTypes;
363                         for (int j = 0; j < descs.length; ++j) {
364                             superTypes.add(descs[j]);
365                         }
366                         superTypes.add(desc);
367                     }
368                 }
369                 // assert !zClass.getName().startsWith("[");
370                 return new TypeDescription(
371                     typeClass, typeName, "[L" + zClass.getName() + ";", zClass,
372                     superTypes.toArray(), null);
373             }
374 
375         default:
376             throw new IllegalArgumentException("given type has bad type class");
377         }
378     }
379 
TypeDescription( TypeClass typeClass, String typeName, String arrayTypeName, Class zClass, TypeDescription[] superTypes, ITypeDescription componentType)380     private TypeDescription(
381         TypeClass typeClass, String typeName, String arrayTypeName,
382         Class zClass, TypeDescription[] superTypes,
383         ITypeDescription componentType)
384     {
385         this.typeClass = typeClass;
386         this.typeName = typeName;
387         this.arrayTypeName = arrayTypeName;
388         this.zClass = zClass;
389         this.superTypes = superTypes;
390         this.componentType = componentType;
391         TypeDescription[] args = calculateTypeArguments();
392         this.hasTypeArguments = args != null;
393         this.fieldDescriptions = calculateFieldDescriptions(args);
394         // methodDescriptions must be initialized lazily, to avoid problems with
395         // circular dependencies (a super-interface that has a sub-interface as
396         // method parameter type; an interface that has a struct as method
397         // parameter type, and the struct has the interface as member type)
398     }
399 
initMethodDescriptions()400     private synchronized void initMethodDescriptions() {
401         if (methodDescriptions != null || typeClass != TypeClass.INTERFACE) {
402             return;
403         }
404         if (superTypes.length == 0) { // com.sun.star.uno.XInterface
405             superMethodDescriptions = new IMethodDescription[0];
406             methodDescriptions = new IMethodDescription[] {
407                 new MethodDescription(
408                     "queryInterface", MethodDescription.ID_QUERY_INTERFACE,
409                     false, new ITypeDescription[] { getDefinitely(Type.TYPE) },
410                     new ITypeDescription[] { null }, getDefinitely(Type.ANY),
411                     null),
412                 new MethodDescription(
413                     "acquire", MethodDescription.ID_ACQUIRE, true,
414                     new ITypeDescription[0], new ITypeDescription[0],
415                     getDefinitely(Type.VOID), null),
416                 new MethodDescription(
417                     "release", MethodDescription.ID_RELEASE, true,
418                     new ITypeDescription[0], new ITypeDescription[0],
419                     getDefinitely(Type.VOID), null) };
420         } else {
421             int methodOffset = 0;
422             ArrayList superList = new ArrayList();
423             for (int i = 0; i < superTypes.length; ++i) {
424                 IMethodDescription[] ds = superTypes[i].getMethodDescriptions();
425                 for (int j = 0; j < ds.length; ++j) {
426                     superList.add(new MethodDescription(ds[j], methodOffset++));
427                 }
428             }
429             superMethodDescriptions = (IMethodDescription[]) superList.toArray(
430                 new IMethodDescription[superList.size()]);
431             ArrayList directList = new ArrayList();
432             TypeInfo[] infos = getTypeInfo();
433             int infoCount = infos == null ? 0 : infos.length;
434             int index = 0;
435             Method[] methods = zClass.getDeclaredMethods();
436             for (int i = 0; i < infoCount;) {
437                 if (infos[i] instanceof AttributeTypeInfo) {
438                     AttributeTypeInfo info = (AttributeTypeInfo) infos[i++];
439                     if (info.getIndex() != index) {
440                         throw new IllegalArgumentException(
441                             "Bad UNOTYPEINFO for " + zClass
442                             + ": entries not ordererd");
443                     }
444                     String getterName = "get" + info.getName();
445                     Method getter = findMethod(methods, getterName);
446                     Type t = info.getUnoType();
447                     ITypeDescription type = t == null
448                         ? getTypeDescription(getter.getReturnType(), info)
449                         : getDefinitely(t);
450                     directList.add(
451                         new MethodDescription(
452                             getterName, index++ + methodOffset, false,
453                             new ITypeDescription[0], new ITypeDescription[0],
454                             type, getter));
455                     if (!info.isReadOnly()) {
456                         String setterName = "set" + info.getName();
457                         Method setter = findMethod(methods, setterName);
458                         directList.add(
459                             new MethodDescription(
460                                 setterName, index++ + methodOffset, false,
461                                 new ITypeDescription[] { type },
462                                 new ITypeDescription[] { null },
463                                 getDefinitely(Type.VOID), setter));
464                     }
465                 } else {
466                     MethodTypeInfo info = (MethodTypeInfo) infos[i++];
467                     if (info.getIndex() != index) {
468                         throw new IllegalArgumentException(
469                             "Bad UNOTYPEINFO for " + zClass
470                             + ": entries not ordererd");
471                     }
472                     Method method = findMethod(methods, info.getName());
473                     Class[] params = method.getParameterTypes();
474                     ITypeDescription[] in = new ITypeDescription[params.length];
475                     ITypeDescription[] out
476                         = new ITypeDescription[params.length];
477                     for (int j = 0; j < params.length; ++j) {
478                         ParameterTypeInfo p = null;
479                         if (i < infoCount
480                             && infos[i] instanceof ParameterTypeInfo
481                             && ((ParameterTypeInfo) infos[i]).getIndex() == j)
482                         {
483                             p = (ParameterTypeInfo) infos[i++];
484                         }
485                         Type pt = p == null ? null : p.getUnoType();
486                         ITypeDescription d = pt == null
487                             ? getTypeDescription(params[j], p)
488                             : getDefinitely(pt);
489                         if (p == null || p.isIN()) {
490                             in[j] = d;
491                         }
492                         if (p != null && p.isOUT()) {
493                             out[j] = d;
494                         }
495                     }
496                     Type t = info.getUnoType();
497                     directList.add(
498                         new MethodDescription(
499                             info.getName(), index++ + methodOffset,
500                             info.isOneway(), in, out,
501                             (t == null
502                              ? getTypeDescription(method.getReturnType(), info)
503                              : getDefinitely(t)),
504                             method));
505                 }
506             }
507             methodDescriptions = (IMethodDescription[]) directList.toArray(
508                 new IMethodDescription[directList.size()]);
509         }
510     }
511 
calculateTypeArguments()512     private TypeDescription[] calculateTypeArguments() {
513         if (typeClass != TypeClass.STRUCT) {
514             return null;
515         }
516         int i = typeName.indexOf('<');
517         if (i < 0) {
518             return null;
519         }
520         java.util.List args = new java.util.ArrayList();
521         do {
522             ++i; // skip '<' or ','
523             int j = i;
524         loop:
525             for (int level = 0; j != typeName.length(); ++j) {
526                 switch (typeName.charAt(j)) {
527                 case ',':
528                     if (level == 0) {
529                         break loop;
530                     }
531                     break;
532 
533                 case '<':
534                     ++level;
535                     break;
536 
537                 case '>':
538                     if (level == 0) {
539                         break loop;
540                     }
541                     --level;
542                     break;
543                 }
544             }
545             if (j != typeName.length()) {
546                 Type t = new Type(typeName.substring(i, j));
547                 if (t.getZClass() == null) {
548                     throw new IllegalArgumentException(
549                         "UNO type name \"" + typeName
550                         + "\" contains bad type argument \""
551                         + typeName.substring(i, j) + "\"");
552                 }
553                 args.add(getDefinitely(t));
554             }
555             i = j;
556         } while (i != typeName.length() && typeName.charAt(i) != '>');
557         if (i != typeName.length() - 1 || typeName.charAt(i) != '>'
558             || args.isEmpty())
559         {
560             throw new IllegalArgumentException(
561                 "UNO type name \"" + typeName + "\" is syntactically invalid");
562         }
563         return (TypeDescription[]) args.toArray(
564                 new TypeDescription[args.size()]);
565     }
566 
calculateFieldDescriptions( TypeDescription[] typeArguments)567     private IFieldDescription[] calculateFieldDescriptions(
568         TypeDescription[] typeArguments)
569     {
570         if (typeClass != TypeClass.STRUCT && typeClass != TypeClass.EXCEPTION) {
571             return null;
572         }
573         TypeInfo[] infos = getTypeInfo();
574         int infoCount = infos == null ? 0 : infos.length;
575         ITypeDescription superType = getSuperType();
576         IFieldDescription[] superDescs = superType == null
577             ? null : superType.getFieldDescriptions();
578         int superCount = superDescs == null ? 0 : superDescs.length;
579         IFieldDescription[] descs = new IFieldDescription[
580             superCount + infoCount];
581         if (superCount != 0) {
582             System.arraycopy(superDescs, 0, descs, 0, superCount);
583         }
584         for (int i = 0; i < infoCount; ++i) {
585             MemberTypeInfo info = (MemberTypeInfo) infos[i];
586             if (info.getIndex() != i) {
587                 throw new IllegalArgumentException(
588                     "Bad UNOTYPEINFO for " + zClass + ": entries not ordererd");
589             }
590             Field field;
591             try {
592                 field = zClass.getDeclaredField(info.getName());
593             } catch (NoSuchFieldException e) {
594                 throw new IllegalArgumentException(
595                     "Bad UNOTYPEINFO for " + zClass + ": " + e);
596             }
597             Type t = info.getUnoType();
598             int index = info.getTypeParameterIndex();
599             descs[i + superCount] = new FieldDescription(
600                 info.getName(), i + superCount,
601                 (index >= 0
602                  ? typeArguments[index]
603                  : t == null
604                  ? getTypeDescription(field.getType(), info)
605                  : getDefinitely(t)),
606                 field);
607         }
608         return descs;
609     }
610 
getTypeInfo()611     private TypeInfo[] getTypeInfo() {
612         try {
613             return (TypeInfo[])
614                 zClass.getDeclaredField("UNOTYPEINFO").get(null);
615         } catch (NoSuchFieldException e) {
616             return null;
617         } catch (IllegalAccessException e) {
618             throw new IllegalArgumentException(
619                 "Bad UNOTYPEINFO for " + zClass + ": " + e);
620         }
621     }
622 
findMethod(Method[] methods, String name)623     private Method findMethod(Method[] methods, String name) {
624         for (int i = 0; i < methods.length; ++i) {
625             if (methods[i].getName().equals(name)) {
626                 return methods[i];
627             }
628         }
629         throw new IllegalArgumentException(
630             "Bad UNOTYPEINFO for " + zClass + ": no method " + name);
631     }
632 
getTypeDescription( Class zClass, TypeInfo typeInfo)633     private static ITypeDescription getTypeDescription(
634         Class zClass, TypeInfo typeInfo)
635     {
636         return getDefinitely(
637             new Type(
638                 zClass,
639                 typeInfo != null
640                 && (typeInfo.isUnsigned() || typeInfo.isInterface())));
641     }
642 
643     private static final class List {
List()644         public List() {}
645 
add(TypeDescription desc)646         public void add(TypeDescription desc) {
647             if (!list.contains(desc)) {
648                 list.add(desc);
649             }
650         }
651 
isEmpty()652         public boolean isEmpty() {
653             return list.isEmpty();
654         }
655 
toArray()656         public TypeDescription[] toArray() {
657             return (TypeDescription[]) list.toArray(
658                 new TypeDescription[list.size()]);
659         }
660 
661         private final ArrayList list = new ArrayList();
662     }
663 
664     private static final class Cache {
Cache()665         public Cache() {}
666 
get(String typeName)667         public TypeDescription get(String typeName) {
668             synchronized (map) {
669                 cleanUp();
670                 Entry e = (Entry) map.get(typeName);
671                 return e == null ? null : (TypeDescription) e.get();
672             }
673         }
674 
put(TypeDescription desc)675         public void put(TypeDescription desc) {
676             synchronized (map) {
677                 cleanUp();
678                 map.put(desc.getTypeName(), new Entry(desc, queue));
679             }
680         }
681 
cleanUp()682         private void cleanUp() {
683             for (;;) {
684                 Entry e = (Entry) queue.poll();
685                 if (e == null) {
686                     break;
687                 }
688                 map.remove(e.typeName);
689             }
690         }
691 
692         private static final class Entry extends SoftReference {
Entry(TypeDescription desc, ReferenceQueue queue)693             public Entry(TypeDescription desc, ReferenceQueue queue) {
694                 super(desc, queue);
695                 typeName = desc.getTypeName();
696             }
697 
698             public final String typeName;
699         }
700 
701         private final HashMap map = new HashMap();
702         private final ReferenceQueue queue = new ReferenceQueue();
703     }
704 
705     private static final Cache cache = new Cache();
706 
707     private final TypeClass typeClass;
708     private final String typeName;
709     private final String arrayTypeName;
710     private final Class zClass;
711     private final TypeDescription[] superTypes;
712     private final ITypeDescription componentType;
713     private final boolean hasTypeArguments;
714     private final IFieldDescription[] fieldDescriptions;
715     private IMethodDescription[] methodDescriptions = null;
716     private IMethodDescription[] superMethodDescriptions;
717 }
718