Source Code Cross Referenced for TypeOracle.java in  » Ajax » GWT » com » google » gwt » core » ext » typeinfo » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Ajax » GWT » com.google.gwt.core.ext.typeinfo 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2007 Google Inc.
0003:         * 
0004:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0005:         * use this file except in compliance with the License. You may obtain a copy of
0006:         * the License at
0007:         * 
0008:         * http://www.apache.org/licenses/LICENSE-2.0
0009:         * 
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0012:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0013:         * License for the specific language governing permissions and limitations under
0014:         * the License.
0015:         */
0016:        package com.google.gwt.core.ext.typeinfo;
0017:
0018:        import com.google.gwt.core.ext.TreeLogger;
0019:        import com.google.gwt.core.ext.UnableToCompleteException;
0020:
0021:        import java.lang.annotation.Annotation;
0022:        import java.util.ArrayList;
0023:        import java.util.Arrays;
0024:        import java.util.Comparator;
0025:        import java.util.HashMap;
0026:        import java.util.HashSet;
0027:        import java.util.IdentityHashMap;
0028:        import java.util.Iterator;
0029:        import java.util.List;
0030:        import java.util.Map;
0031:        import java.util.Set;
0032:
0033:        /**
0034:         * Provides type-related information about a set of source files, including doc
0035:         * comment metadata.
0036:         * <p>
0037:         * All type objects exposed, such as
0038:         * {@link com.google.gwt.core.ext.typeinfo.JClassType} and others, have a stable
0039:         * identity relative to this type oracle instance. Consequently, you can
0040:         * reliably compare object identity of any objects this type oracle produces.
0041:         * For example, the following code relies on this stable identity guarantee:
0042:         * 
0043:         * <pre>
0044:         * JClassType o = typeOracle.getJavaLangObject();
0045:         * JClassType s1 = typeOracle.getType(&quot;java.lang.String&quot;);
0046:         * JClassType s2 = typeOracle.getType(&quot;java.lang.String&quot;);
0047:         * assert(s1 == s2);
0048:         * assert(o == s1.getSuperclass());
0049:         * JParameterizedType ls = typeOracle.parse(&quot;java.util.List&lt;java.lang.String&gt;&quot;);
0050:         * assert(ls.getTypeArgs()[0] == s1);
0051:         * </pre>
0052:         * 
0053:         * </p>
0054:         */
0055:        public class TypeOracle {
0056:            /**
0057:             * A reserved metadata tag to indicates that a field type, method return type
0058:             * or method parameter type is intended to be parameterized. Note that
0059:             * constructor type parameters are not supported at present.
0060:             */
0061:            public static final String TAG_TYPEARGS = "gwt.typeArgs";
0062:            static final int MOD_ABSTRACT = 0x00000001;
0063:            static final int MOD_FINAL = 0x00000002;
0064:            static final int MOD_NATIVE = 0x00000004;
0065:            static final int MOD_PRIVATE = 0x00000008;
0066:            static final int MOD_PROTECTED = 0x00000010;
0067:            static final int MOD_PUBLIC = 0x00000020;
0068:            static final int MOD_STATIC = 0x00000040;
0069:            static final int MOD_TRANSIENT = 0x00000080;
0070:
0071:            static final int MOD_VOLATILE = 0x00000100;
0072:            static final Annotation[] NO_ANNOTATIONS = new Annotation[0];
0073:            static final JClassType[] NO_JCLASSES = new JClassType[0];
0074:            static final JConstructor[] NO_JCTORS = new JConstructor[0];
0075:            static final JField[] NO_JFIELDS = new JField[0];
0076:            static final JMethod[] NO_JMETHODS = new JMethod[0];
0077:            static final JPackage[] NO_JPACKAGES = new JPackage[0];
0078:            static final JParameter[] NO_JPARAMS = new JParameter[0];
0079:            static final JType[] NO_JTYPES = new JType[0];
0080:            static final String[][] NO_STRING_ARR_ARR = new String[0][];
0081:            static final String[] NO_STRINGS = new String[0];
0082:
0083:            static String combine(String[] strings, int startIndex) {
0084:                StringBuffer sb = new StringBuffer();
0085:                for (int i = startIndex; i < strings.length; i++) {
0086:                    String s = strings[i];
0087:                    sb.append(s);
0088:                }
0089:                return sb.toString();
0090:            }
0091:
0092:            static String[] modifierBitsToNames(int bits) {
0093:                List<String> strings = new ArrayList<String>();
0094:
0095:                // The order is based on the order in which we want them to appear.
0096:                //
0097:                if (0 != (bits & MOD_PUBLIC)) {
0098:                    strings.add("public");
0099:                }
0100:
0101:                if (0 != (bits & MOD_PRIVATE)) {
0102:                    strings.add("private");
0103:                }
0104:
0105:                if (0 != (bits & MOD_PROTECTED)) {
0106:                    strings.add("protected");
0107:                }
0108:
0109:                if (0 != (bits & MOD_STATIC)) {
0110:                    strings.add("static");
0111:                }
0112:
0113:                if (0 != (bits & MOD_ABSTRACT)) {
0114:                    strings.add("abstract");
0115:                }
0116:
0117:                if (0 != (bits & MOD_FINAL)) {
0118:                    strings.add("final");
0119:                }
0120:
0121:                if (0 != (bits & MOD_NATIVE)) {
0122:                    strings.add("native");
0123:                }
0124:
0125:                if (0 != (bits & MOD_TRANSIENT)) {
0126:                    strings.add("transient");
0127:                }
0128:
0129:                if (0 != (bits & MOD_VOLATILE)) {
0130:                    strings.add("volatile");
0131:                }
0132:
0133:                return strings.toArray(NO_STRINGS);
0134:            }
0135:
0136:            /**
0137:             * Returns true if the type has been invalidated because it is in the set of
0138:             * invalid types or if it is a parameterized type and either it raw type or
0139:             * any one of its type args has been invalidated.
0140:             * 
0141:             * @param type type to check
0142:             * @param invalidTypes set of type known to be invalid
0143:             * @return true if the type has been invalidated
0144:             */
0145:            private static boolean isInvalidatedTypeRecursive(JType type,
0146:                    Set<JClassType> invalidTypes) {
0147:                if (type instanceof  JParameterizedType) {
0148:                    JParameterizedType parameterizedType = (JParameterizedType) type;
0149:                    if (isInvalidatedTypeRecursive(parameterizedType
0150:                            .getBaseType(), invalidTypes)) {
0151:                        return true;
0152:                    }
0153:
0154:                    JType[] typeArgs = parameterizedType.getTypeArgs();
0155:                    for (int i = 0; i < typeArgs.length; ++i) {
0156:                        JType typeArg = typeArgs[i];
0157:
0158:                        if (isInvalidatedTypeRecursive(typeArg, invalidTypes)) {
0159:                            return true;
0160:                        }
0161:                    }
0162:
0163:                    return false;
0164:                } else {
0165:                    return invalidTypes.contains(type);
0166:                }
0167:            }
0168:
0169:            private final Map<JType, JArrayType> arrayTypes = new IdentityHashMap<JType, JArrayType>();
0170:
0171:            private JClassType javaLangObject;
0172:
0173:            private final Map<String, JPackage> packages = new HashMap<String, JPackage>();
0174:
0175:            private final Map<String, List<JParameterizedType>> parameterizedTypes = new HashMap<String, List<JParameterizedType>>();
0176:
0177:            private int reloadCount = 0;
0178:
0179:            private final Map<CompilationUnitProvider, JClassType[]> typesByCup = new IdentityHashMap<CompilationUnitProvider, JClassType[]>();
0180:
0181:            private final Map<String, List<JWildcardType>> wildcardTypes = new HashMap<String, List<JWildcardType>>();
0182:
0183:            public TypeOracle() {
0184:                // Always create the default package.
0185:                //
0186:                getOrCreatePackage("");
0187:            }
0188:
0189:            /**
0190:             * Attempts to find a package by name. All requests for the same package
0191:             * return the same package object.
0192:             * 
0193:             * @return <code>null</code> if the package could not be found
0194:             */
0195:            public JPackage findPackage(String pkgName) {
0196:                return packages.get(pkgName);
0197:            }
0198:
0199:            /**
0200:             * Finds a class or interface given its fully-qualified name. For nested
0201:             * classes, use its source name rather than its binary name (that is, use a
0202:             * "." rather than a "$").
0203:             * 
0204:             * @return <code>null</code> if the type is not found
0205:             */
0206:            public JClassType findType(String name) {
0207:                // Try the dotted pieces, right to left.
0208:                //
0209:                int i = name.length() - 1;
0210:                while (i >= 0) {
0211:                    int dot = name.lastIndexOf('.', i);
0212:                    String pkgName = "";
0213:                    String typeName = name;
0214:                    if (dot != -1) {
0215:                        pkgName = name.substring(0, dot);
0216:                        typeName = name.substring(dot + 1);
0217:                        i = dot - 1;
0218:                    } else {
0219:                        i = -1;
0220:                    }
0221:                    JClassType result = findType(pkgName, typeName);
0222:                    if (result != null) {
0223:                        return result;
0224:                    }
0225:                }
0226:                return null;
0227:            }
0228:
0229:            /**
0230:             * Finds a type given its package-relative name. For nested classes, use its
0231:             * source name rather than its binary name (that is, use a "." rather than a
0232:             * "$").
0233:             * 
0234:             * @return <code>null</code> if the type is not found
0235:             */
0236:            public JClassType findType(String pkgName, String typeName) {
0237:                JPackage pkg = findPackage(pkgName);
0238:                if (pkg != null) {
0239:                    JClassType type = pkg.findType(typeName);
0240:                    if (type != null) {
0241:                        return type;
0242:                    }
0243:                }
0244:                return null;
0245:            }
0246:
0247:            /**
0248:             * Gets the type object that represents an array of the specified type. The
0249:             * returned type always has a stable identity so as to guarantee that all
0250:             * calls to this method with the same argument return the same object.
0251:             * 
0252:             * @param componentType the component type of the array, which can itself be
0253:             *          an array type
0254:             * @return a type object representing an array of the component type
0255:             */
0256:            public JArrayType getArrayType(JType componentType) {
0257:                JArrayType arrayType = arrayTypes.get(componentType);
0258:                if (arrayType == null) {
0259:                    arrayType = new JArrayType(componentType, this );
0260:                    arrayTypes.put(componentType, arrayType);
0261:                }
0262:                return arrayType;
0263:            }
0264:
0265:            /**
0266:             * Gets a reference to the type object representing
0267:             * <code>java.lang.Object</code>.
0268:             */
0269:            public JClassType getJavaLangObject() {
0270:                return javaLangObject;
0271:            }
0272:
0273:            /**
0274:             * Ensure that a package with the specified name exists as well as its parent
0275:             * packages.
0276:             */
0277:            public JPackage getOrCreatePackage(String name) {
0278:                int i = name.lastIndexOf('.');
0279:                if (i != -1) {
0280:                    // Ensure the parent package is also created.
0281:                    //
0282:                    getOrCreatePackage(name.substring(0, i));
0283:                }
0284:
0285:                JPackage pkg = packages.get(name);
0286:                if (pkg == null) {
0287:                    pkg = new JPackage(name);
0288:                    packages.put(name, pkg);
0289:                }
0290:                return pkg;
0291:            }
0292:
0293:            /**
0294:             * Gets a package by name. All requests for the same package return the same
0295:             * package object.
0296:             * 
0297:             * @return the package object associated with the specified name
0298:             */
0299:            public JPackage getPackage(String pkgName) throws NotFoundException {
0300:                JPackage result = findPackage(pkgName);
0301:                if (result == null) {
0302:                    throw new NotFoundException(pkgName);
0303:                }
0304:                return result;
0305:            }
0306:
0307:            /**
0308:             * Gets an array of all packages known to this type oracle.
0309:             * 
0310:             * @return an array of packages, possibly of zero-length
0311:             */
0312:            public JPackage[] getPackages() {
0313:                return packages.values().toArray(NO_JPACKAGES);
0314:            }
0315:
0316:            /**
0317:             * Gets the parameterized type object that represents the combination of a
0318:             * specified raw type and a set of type arguments. The returned type always
0319:             * has a stable identity so as to guarantee that all calls to this method with
0320:             * the same arguments return the same object.
0321:             * 
0322:             * @param genericType a generic base class
0323:             * @param enclosingType
0324:             * @param typeArgs the type arguments bound to the specified generic type
0325:             * @return a type object representing this particular binding of type
0326:             *         arguments to the specified generic
0327:             * @throws IllegalArgumentException if the parameterization of a non-static
0328:             *           member type does not specify an enclosing type or if not enough
0329:             *           arguments were specified to parameterize the generic type
0330:             * @throws NullPointerException if genericType is <code>null</code>
0331:             */
0332:            public JParameterizedType getParameterizedType(
0333:                    JGenericType genericType, JClassType enclosingType,
0334:                    JClassType[] typeArgs) {
0335:                if (genericType == null) {
0336:                    throw new NullPointerException("genericType");
0337:                }
0338:
0339:                if (genericType.isMemberType() && !genericType.isStatic()) {
0340:                    if (genericType.getEnclosingType().isGenericType() != null
0341:                            && enclosingType.isParameterized() == null
0342:                            && enclosingType.isRawType() == null) {
0343:                        throw new IllegalArgumentException(
0344:                                "enclosingType needs to be a parameterized type or a raw type");
0345:                    }
0346:                }
0347:
0348:                JTypeParameter[] typeParameters = genericType
0349:                        .getTypeParameters();
0350:                if (typeArgs.length < typeParameters.length) {
0351:                    throw new IllegalArgumentException(
0352:                            "Not enough type arguments were specified to parameterize '"
0353:                                    + genericType
0354:                                            .getParameterizedQualifiedSourceName()
0355:                                    + "'");
0356:                } else {
0357:                    /*
0358:                     * TODO: Should WARN if we specify too many type arguments but we have no
0359:                     * logger.
0360:                     */
0361:                }
0362:
0363:                // TODO: validate that the type arguments satisfy the generic type parameter
0364:                // bounds if any were specified
0365:
0366:                // Uses the generated string signature to intern parameterized types.
0367:                //
0368:                JParameterizedType parameterized = new JParameterizedType(
0369:                        genericType, enclosingType, typeArgs);
0370:
0371:                // TODO: parameterized qualified source name does not account for the type
0372:                // args of the enclosing type
0373:                String sig = parameterized
0374:                        .getParameterizedQualifiedSourceName();
0375:                List<JParameterizedType> candidates = parameterizedTypes
0376:                        .get(sig);
0377:                if (candidates == null) {
0378:                    candidates = new ArrayList<JParameterizedType>();
0379:                    parameterizedTypes.put(sig, candidates);
0380:                } else {
0381:                    for (JParameterizedType candidate : candidates) {
0382:                        if (candidate.hasTypeArgs(typeArgs)) {
0383:                            return candidate;
0384:                        }
0385:                    }
0386:                }
0387:
0388:                candidates.add(parameterized);
0389:
0390:                return parameterized;
0391:            }
0392:
0393:            /**
0394:             * Gets the parameterized type object that represents the combination of a
0395:             * specified raw type and a set of type arguments. The returned type always
0396:             * has a stable identity so as to guarantee that all calls to this method with
0397:             * the same arguments return the same object.
0398:             * 
0399:             * @param genericType a generic base class
0400:             * @param typeArgs the type arguments bound to the specified generic type
0401:             * @return a type object representing this particular binding of type
0402:             *         arguments to the specified generic
0403:             * @throws IllegalArgumentException if the generic type is a non-static member
0404:             *           type or if not enough arguments were specified to parameterize
0405:             *           the generic type
0406:             * @throws NullPointerException if genericType is <code>null</code>
0407:             */
0408:            public JParameterizedType getParameterizedType(
0409:                    JGenericType genericType, JClassType[] typeArgs) {
0410:                return getParameterizedType(genericType, null, typeArgs);
0411:            }
0412:
0413:            public long getReloadCount() {
0414:                return reloadCount;
0415:            }
0416:
0417:            /**
0418:             * Finds a type given its fully qualified name. For nested classes, use its
0419:             * source name rather than its binary name (that is, use a "." rather than a
0420:             * "$").
0421:             * 
0422:             * @return the specified type
0423:             */
0424:            public JClassType getType(String name) throws NotFoundException {
0425:                JClassType type = findType(name);
0426:                if (type == null) {
0427:                    throw new NotFoundException(name);
0428:                }
0429:                return type;
0430:            }
0431:
0432:            /**
0433:             * Finds a type given its package-relative name. For nested classes, use its
0434:             * source name rather than its binary name (that is, use a "." rather than a
0435:             * "$").
0436:             * 
0437:             * @return the specified type
0438:             */
0439:            public JClassType getType(String pkgName,
0440:                    String topLevelTypeSimpleName) throws NotFoundException {
0441:                JClassType type = findType(pkgName, topLevelTypeSimpleName);
0442:                if (type == null) {
0443:                    throw new NotFoundException(pkgName + "."
0444:                            + topLevelTypeSimpleName);
0445:                }
0446:                return type;
0447:            }
0448:
0449:            /**
0450:             * Gets all types, both top-level and nested.
0451:             * 
0452:             * @return an array of types, possibly of zero length
0453:             */
0454:            public JClassType[] getTypes() {
0455:                Set<JClassType> allTypes = new HashSet<JClassType>();
0456:                JPackage[] pkgs = getPackages();
0457:                for (int i = 0; i < pkgs.length; i++) {
0458:                    JPackage pkg = pkgs[i];
0459:                    JClassType[] types = pkg.getTypes();
0460:                    for (int j = 0; j < types.length; j++) {
0461:                        JClassType type = types[j];
0462:                        buildAllTypesImpl(allTypes, type);
0463:                    }
0464:                }
0465:                return allTypes.toArray(NO_JCLASSES);
0466:            }
0467:
0468:            public JClassType[] getTypesInCompilationUnit(
0469:                    CompilationUnitProvider cup) {
0470:                JClassType[] types = typesByCup.get(cup);
0471:                if (types != null) {
0472:                    return types;
0473:                } else {
0474:                    return NO_JCLASSES;
0475:                }
0476:            }
0477:
0478:            public JWildcardType getWildcardType(JBound bounds) {
0479:                JWildcardType wildcardType = new JWildcardType(bounds);
0480:                String sig = wildcardType.getQualifiedSourceName();
0481:                List<JWildcardType> candidates = wildcardTypes.get(sig);
0482:                if (candidates == null) {
0483:                    candidates = new ArrayList<JWildcardType>();
0484:                    wildcardTypes.put(sig, candidates);
0485:                } else {
0486:                    for (JWildcardType candidate : candidates) {
0487:                        if (candidate.hasBounds(bounds)) {
0488:                            return candidate;
0489:                        }
0490:                    }
0491:                }
0492:
0493:                candidates.add(wildcardType);
0494:
0495:                return wildcardType;
0496:            }
0497:
0498:            /**
0499:             * Parses the string form of a type to produce the corresponding type object.
0500:             * The types that can be parsed include primitives, class and interface names,
0501:             * simple parameterized types (those without wildcards or bounds), and arrays
0502:             * of the preceding.
0503:             * <p>
0504:             * Examples of types that can be parsed by this method.
0505:             * <ul>
0506:             * <li><code>int</code></li>
0507:             * <li><code>java.lang.Object</code></li>
0508:             * <li><code>java.lang.String[]</code></li>
0509:             * <li><code>char[][]</code></li>
0510:             * <li><code>void</code></li>
0511:             * <li><code>List&lt;Shape&gt;</code></li>
0512:             * <li><code>List&lt;List&lt;Shape&gt;&gt;</code></li>
0513:             * </ul>
0514:             * </p>
0515:             * 
0516:             * @param type a type signature to be parsed
0517:             * @return the type object corresponding to the parse type
0518:             */
0519:            public JType parse(String type) throws TypeOracleException {
0520:                // Remove all internal and external whitespace.
0521:                //
0522:                type = type.replaceAll("\\\\s", "");
0523:
0524:                // Recursively parse.
0525:                //
0526:                return parseImpl(type);
0527:            }
0528:
0529:            /**
0530:             * Convenience method to sort class types in a consistent way. Note that the
0531:             * order is subject to change and is intended to generate an "aesthetically
0532:             * pleasing" order rather than a computationally reliable order.
0533:             */
0534:            public void sort(JClassType[] types) {
0535:                Arrays.sort(types, new Comparator<JClassType>() {
0536:                    public int compare(JClassType type1, JClassType type2) {
0537:                        String name1 = type1.getQualifiedSourceName();
0538:                        String name2 = type2.getQualifiedSourceName();
0539:                        return name1.compareTo(name2);
0540:                    }
0541:                });
0542:            }
0543:
0544:            /**
0545:             * Convenience method to sort constructors in a consistent way. Note that the
0546:             * order is subject to change and is intended to generate an "aesthetically
0547:             * pleasing" order rather than a computationally reliable order.
0548:             */
0549:            public void sort(JConstructor[] ctors) {
0550:                Arrays.sort(ctors, new Comparator<JConstructor>() {
0551:                    public int compare(JConstructor o1, JConstructor o2) {
0552:                        // Nothing for now; could enhance to sort based on parameter list
0553:                        return 0;
0554:                    }
0555:                });
0556:            }
0557:
0558:            /**
0559:             * Convenience method to sort fields in a consistent way. Note that the order
0560:             * is subject to change and is intended to generate an "aesthetically
0561:             * pleasing" order rather than a computationally reliable order.
0562:             */
0563:            public void sort(JField[] fields) {
0564:                Arrays.sort(fields, new Comparator<JField>() {
0565:                    public int compare(JField f1, JField f2) {
0566:                        String name1 = f1.getName();
0567:                        String name2 = f2.getName();
0568:                        return name1.compareTo(name2);
0569:                    }
0570:                });
0571:            }
0572:
0573:            /**
0574:             * Convenience method to sort methods in a consistent way. Note that the order
0575:             * is subject to change and is intended to generate an "aesthetically
0576:             * pleasing" order rather than a computationally reliable order.
0577:             */
0578:            public void sort(JMethod[] methods) {
0579:                Arrays.sort(methods, new Comparator<JMethod>() {
0580:                    public int compare(JMethod m1, JMethod m2) {
0581:                        String name1 = m1.getName();
0582:                        String name2 = m2.getName();
0583:                        return name1.compareTo(name2);
0584:                    }
0585:                });
0586:            }
0587:
0588:            void incrementReloadCount() {
0589:                reloadCount++;
0590:            }
0591:
0592:            /**
0593:             * Note, this method is called reflectively from the
0594:             * {@link CacheManager#invalidateOnRefresh(TypeOracle)}.
0595:             * 
0596:             * @param cup compilation unit whose types will be invalidated
0597:             */
0598:            void invalidateTypesInCompilationUnit(CompilationUnitProvider cup) {
0599:                Set<JClassType> invalidTypes = new HashSet<JClassType>();
0600:                JClassType[] types = typesByCup.get(cup);
0601:                if (types == null) {
0602:                    return;
0603:                }
0604:
0605:                for (int i = 0; i < types.length; i++) {
0606:                    JClassType classTypeToInvalidate = types[i];
0607:                    invalidTypes.add(classTypeToInvalidate);
0608:                }
0609:
0610:                typesByCup.remove(cup);
0611:
0612:                removeInvalidatedArrayTypes(invalidTypes);
0613:
0614:                removeInvalidatedParameterizedTypes(invalidTypes);
0615:
0616:                removeTypes(invalidTypes);
0617:            }
0618:
0619:            void recordTypeInCompilationUnit(CompilationUnitProvider cup,
0620:                    JClassType type) {
0621:                JClassType[] types = typesByCup.get(cup);
0622:                if (types == null) {
0623:                    types = new JClassType[] { type };
0624:                } else {
0625:                    JClassType[] temp = new JClassType[types.length + 1];
0626:                    System.arraycopy(types, 0, temp, 0, types.length);
0627:                    temp[types.length] = type;
0628:                    types = temp;
0629:                }
0630:                typesByCup.put(cup, types);
0631:            }
0632:
0633:            /**
0634:             * Updates relationships within this type oracle. Should be called after any
0635:             * changes are made.
0636:             * 
0637:             * <p>
0638:             * Throws <code>TypeOracleException</code> thrown if fundamental baseline
0639:             * correctness criteria are violated, most notably the absence of
0640:             * "java.lang.Object"
0641:             * </p>
0642:             */
0643:            void refresh(TreeLogger logger) throws NotFoundException {
0644:                if (javaLangObject == null) {
0645:                    javaLangObject = findType("java.lang.Object");
0646:                    if (javaLangObject == null) {
0647:                        throw new NotFoundException("java.lang.Object");
0648:                    }
0649:                }
0650:                computeHierarchyRelationships();
0651:                consumeTypeArgMetaData(logger);
0652:            }
0653:
0654:            private void buildAllTypesImpl(Set<JClassType> allTypes,
0655:                    JClassType type) {
0656:                boolean didAdd = allTypes.add(type);
0657:                assert (didAdd);
0658:                JClassType[] nestedTypes = type.getNestedTypes();
0659:                for (int i = 0; i < nestedTypes.length; i++) {
0660:                    JClassType nestedType = nestedTypes[i];
0661:                    buildAllTypesImpl(allTypes, nestedType);
0662:                }
0663:            }
0664:
0665:            private void computeHierarchyRelationships() {
0666:                // For each type, walk up its hierarchy chain and tell each supertype
0667:                // about its subtype.
0668:                //
0669:                JClassType[] allTypes = getTypes();
0670:                for (int i = 0; i < allTypes.length; i++) {
0671:                    JClassType type = allTypes[i];
0672:                    type.notifySuperTypes();
0673:                }
0674:            }
0675:
0676:            private void consumeTypeArgMetaData(TreeLogger logger) {
0677:                logger = logger.branch(TreeLogger.DEBUG, "Examining "
0678:                        + TAG_TYPEARGS + " tags", null);
0679:                consumeTypeArgMetaData(logger, getTypes());
0680:            }
0681:
0682:            private void consumeTypeArgMetaData(TreeLogger logger,
0683:                    JClassType[] types) {
0684:                for (int i = 0; i < types.length; i++) {
0685:                    JClassType type = types[i];
0686:                    // CTORS not supported yet
0687:
0688:                    TreeLogger branch = logger.branch(TreeLogger.DEBUG, "Type "
0689:                            + type.getQualifiedSourceName(), null);
0690:
0691:                    consumeTypeArgMetaData(branch, type.getMethods());
0692:                    consumeTypeArgMetaData(branch, type.getFields());
0693:                }
0694:            }
0695:
0696:            private void consumeTypeArgMetaData(TreeLogger logger,
0697:                    JField[] fields) {
0698:                TreeLogger branch;
0699:                for (int i = 0; i < fields.length; i++) {
0700:                    JField field = fields[i];
0701:
0702:                    String[][] tokensArray = field.getMetaData(TAG_TYPEARGS);
0703:                    if (tokensArray.length == 0) {
0704:                        // No tag.
0705:                        continue;
0706:                    }
0707:
0708:                    try {
0709:                        String msg = "Field " + field.getName();
0710:                        branch = logger.branch(TreeLogger.TRACE, msg, null);
0711:
0712:                        if (tokensArray.length > 1) {
0713:                            // Too many.
0714:                            branch.log(TreeLogger.WARN,
0715:                                    "Metadata error on field '"
0716:                                            + field.getName() + "' in type '"
0717:                                            + field.getEnclosingType()
0718:                                            + "': expecting at most one "
0719:                                            + TAG_TYPEARGS
0720:                                            + " (the last one will be used)",
0721:                                    null);
0722:                        }
0723:
0724:                        // (1) Parse it.
0725:                        // (2) Update the field's type.
0726:                        // If it wasn't a valid parameterized type, parse() would've thrown.
0727:                        //
0728:                        JType fieldType = field.getType();
0729:                        String[] token = tokensArray[tokensArray.length - 1];
0730:                        JType resultingType = determineActualType(branch,
0731:                                fieldType, token, 0);
0732:                        field.setType(resultingType);
0733:                    } catch (UnableToCompleteException e) {
0734:                        // Continue; the problem will have been logged.
0735:                        //
0736:                    }
0737:                }
0738:            }
0739:
0740:            private void consumeTypeArgMetaData(TreeLogger logger,
0741:                    JMethod[] methods) {
0742:                TreeLogger branch;
0743:                for (int i = 0; i < methods.length; i++) {
0744:                    JMethod method = methods[i];
0745:
0746:                    String[][] tokensArray = method.getMetaData(TAG_TYPEARGS);
0747:                    if (tokensArray.length == 0) {
0748:                        // No tag.
0749:                        continue;
0750:                    }
0751:                    try {
0752:                        String msg = "Method "
0753:                                + method.getReadableDeclaration();
0754:                        branch = logger.branch(TreeLogger.TRACE, msg, null);
0755:
0756:                        // Okay, parse each one and correlate it to a part of the decl.
0757:                        //
0758:                        boolean returnTypeHandled = false;
0759:                        Set<JParameter> paramsAlreadySet = new HashSet<JParameter>();
0760:                        for (int j = 0; j < tokensArray.length; j++) {
0761:                            String[] tokens = tokensArray[j];
0762:                            // It is either referring to the return type or a parameter type.
0763:                            //
0764:                            if (tokens.length == 0) {
0765:                                // Expecting at least something.
0766:                                //
0767:                                branch.log(TreeLogger.WARN,
0768:                                        "Metadata error: expecting tokens after "
0769:                                                + TAG_TYPEARGS, null);
0770:                                throw new UnableToCompleteException();
0771:                            }
0772:
0773:                            // See if the first token is a parameter name.
0774:                            //
0775:                            JParameter param = method.findParameter(tokens[0]);
0776:                            if (param != null) {
0777:                                if (!paramsAlreadySet.contains(param)) {
0778:                                    // These are type args for a param.
0779:                                    //
0780:                                    JType resultingType = determineActualType(
0781:                                            branch, param.getType(), tokens, 1);
0782:                                    param.setType(resultingType);
0783:                                    paramsAlreadySet.add(param);
0784:                                } else {
0785:                                    // This parameter type has already been set.
0786:                                    //
0787:                                    msg = "Metadata error: duplicate attempt to specify type args for parameter '"
0788:                                            + param.getName() + "'";
0789:                                    branch.log(TreeLogger.WARN, msg, null);
0790:                                    throw new UnableToCompleteException();
0791:                                }
0792:                            } else {
0793:                                // It's either referring to the return type or a bad param name.
0794:                                //
0795:                                if (!returnTypeHandled) {
0796:                                    JType resultingType = determineActualType(
0797:                                            branch, method.getReturnType(),
0798:                                            tokens, 0);
0799:                                    method.setReturnType(resultingType);
0800:                                    returnTypeHandled = true;
0801:                                } else {
0802:                                    // The return type has already been set.
0803:                                    //
0804:                                    msg = "Metadata error: duplicate attempt to specify type args for the return type";
0805:                                    branch.log(TreeLogger.WARN, msg, null);
0806:                                }
0807:                            }
0808:                        }
0809:                    } catch (UnableToCompleteException e) {
0810:                        // Continue; will already have been logged.
0811:                        //
0812:                    }
0813:                }
0814:            }
0815:
0816:            /*
0817:             * Given a declared type and some number of type arguments determine what the
0818:             * actual type should be.
0819:             */
0820:            private JType determineActualType(TreeLogger logger,
0821:                    JType declType, String[] tokens, int startIndex)
0822:                    throws UnableToCompleteException {
0823:                // These are type args for a param.
0824:                //
0825:                JType leafType = declType.getLeafType();
0826:                String typeName = leafType.getQualifiedSourceName();
0827:                JType resultingType = parseTypeArgTokens(logger, typeName,
0828:                        tokens, startIndex);
0829:                JArrayType arrayType = declType.isArray();
0830:                if (arrayType != null) {
0831:                    arrayType.setLeafType(resultingType);
0832:
0833:                    return declType;
0834:                }
0835:
0836:                return resultingType;
0837:            }
0838:
0839:            private JType parseImpl(String type) throws NotFoundException,
0840:                    ParseException, BadTypeArgsException {
0841:                if (type.endsWith("[]")) {
0842:                    String remainder = type.substring(0, type.length() - 2);
0843:                    JType componentType = parseImpl(remainder);
0844:                    return getArrayType(componentType);
0845:                }
0846:
0847:                if (type.endsWith(">")) {
0848:                    int bracket = type.indexOf('<');
0849:                    if (bracket == -1) {
0850:                        throw new ParseException(
0851:                                "Mismatched brackets; expected '<' to match subsequent '>'");
0852:                    }
0853:
0854:                    // Resolve the raw type.
0855:                    //
0856:                    String rawTypeName = type.substring(0, bracket);
0857:                    JType rawType = parseImpl(rawTypeName);
0858:                    if (rawType.isParameterized() != null) {
0859:                        // The raw type cannot itself be parameterized.
0860:                        //
0861:                        throw new BadTypeArgsException(
0862:                                "Only non-parameterized classes and interface can be parameterized");
0863:                    } else if (rawType.isClassOrInterface() == null) {
0864:                        // The raw type must be a class or interface
0865:                        // (not an array or primitive).
0866:                        //
0867:                        throw new BadTypeArgsException(
0868:                                "Only classes and interface can be parameterized, so "
0869:                                        + rawType.getQualifiedSourceName()
0870:                                        + " cannot be used in this context");
0871:                    } else if (rawType.isGenericType() == null) {
0872:                        throw new BadTypeArgsException(
0873:                                "'"
0874:                                        + rawType.getQualifiedSourceName()
0875:                                        + "' is not a generic type; only generic types can be parameterized");
0876:                    }
0877:
0878:                    // Resolve each type argument.
0879:                    //
0880:                    String typeArgContents = type.substring(bracket + 1, type
0881:                            .length() - 1);
0882:                    JClassType[] typeArgs = parseTypeArgContents(typeArgContents);
0883:
0884:                    // Intern this type.
0885:                    //
0886:                    return getParameterizedType(rawType.isGenericType(),
0887:                            typeArgs);
0888:                }
0889:
0890:                JType result = JPrimitiveType.valueOf(type);
0891:                if (result != null) {
0892:                    return result;
0893:                }
0894:
0895:                result = findType(type);
0896:                if (result != null) {
0897:                    return result;
0898:                }
0899:
0900:                throw new NotFoundException("Unable to recognize '" + type
0901:                        + "' as a type name (is it fully qualified?)");
0902:            }
0903:
0904:            private void parseTypeArgComponent(List<JClassType> typeArgList,
0905:                    String typeArgComponent) throws NotFoundException,
0906:                    ParseException, BadTypeArgsException {
0907:                JType typeArg = parseImpl(typeArgComponent);
0908:                if (typeArg.isPrimitive() != null) {
0909:                    // Cannot be primitive.
0910:                    //
0911:                    throw new BadTypeArgsException(
0912:                            "Type arguments cannot be primitives, so '"
0913:                                    + typeArg.getQualifiedSourceName()
0914:                                    + "' cannot be used in this context");
0915:                }
0916:
0917:                typeArgList.add((JClassType) typeArg);
0918:            }
0919:
0920:            /**
0921:             * Returns an array of types specified inside of a gwt.typeArgs javadoc
0922:             * annotation.
0923:             */
0924:            private JClassType[] parseTypeArgContents(String typeArgContents)
0925:                    throws ParseException, NotFoundException,
0926:                    BadTypeArgsException {
0927:                List<JClassType> typeArgList = new ArrayList<JClassType>();
0928:
0929:                int start = 0;
0930:                for (int offset = 0, length = typeArgContents.length(); offset < length; ++offset) {
0931:                    char ch = typeArgContents.charAt(offset);
0932:                    switch (ch) {
0933:                    case '<':
0934:                        // scan for closing '>' while ignoring commas
0935:                        for (int depth = 1; depth > 0;) {
0936:                            if (++offset == length) {
0937:                                throw new ParseException(
0938:                                        "Mismatched brackets; expected '<' to match subsequent '>'");
0939:                            }
0940:
0941:                            char ich = typeArgContents.charAt(offset);
0942:                            if (ich == '<') {
0943:                                ++depth;
0944:                            } else if (ich == '>') {
0945:                                --depth;
0946:                            }
0947:                        }
0948:                        break;
0949:                    case '>':
0950:                        throw new ParseException("No matching '<' for '>'");
0951:                    case ',':
0952:                        String typeArgComponent = typeArgContents.substring(
0953:                                start, offset);
0954:                        parseTypeArgComponent(typeArgList, typeArgComponent);
0955:                        start = offset + 1;
0956:                        break;
0957:                    default:
0958:                        break;
0959:                    }
0960:                }
0961:
0962:                String typeArgComponent = typeArgContents.substring(start);
0963:                parseTypeArgComponent(typeArgList, typeArgComponent);
0964:
0965:                JClassType[] typeArgs = typeArgList
0966:                        .toArray(new JClassType[typeArgList.size()]);
0967:                return typeArgs;
0968:            }
0969:
0970:            private JType parseTypeArgTokens(TreeLogger logger,
0971:                    String maybeRawType, String[] tokens, int startIndex)
0972:                    throws UnableToCompleteException {
0973:                String munged = combine(tokens, startIndex).trim();
0974:                String toParse = maybeRawType + munged;
0975:                JType parameterizedType;
0976:                try {
0977:                    parameterizedType = parse(toParse);
0978:                } catch (IllegalArgumentException e) {
0979:                    logger.log(TreeLogger.WARN, e.getMessage(), e);
0980:                    throw new UnableToCompleteException();
0981:                } catch (TypeOracleException e) {
0982:                    logger.log(TreeLogger.WARN, e.getMessage(), e);
0983:                    throw new UnableToCompleteException();
0984:                }
0985:                return parameterizedType;
0986:            }
0987:
0988:            /**
0989:             * Remove any array type whose leaf type has been invalidated.
0990:             * 
0991:             * @param invalidTypes set of types that have been invalidated.
0992:             */
0993:            private void removeInvalidatedArrayTypes(
0994:                    Set<JClassType> invalidTypes) {
0995:                arrayTypes.keySet().removeAll(invalidTypes);
0996:            }
0997:
0998:            /**
0999:             * Remove any parameterized type that was invalidated because either its raw
1000:             * type or any one of its type arguments was invalidated.
1001:             * 
1002:             * @param invalidTypes set of types known to have been invalidated
1003:             */
1004:            private void removeInvalidatedParameterizedTypes(
1005:                    Set<JClassType> invalidTypes) {
1006:                Iterator<List<JParameterizedType>> listIterator = parameterizedTypes
1007:                        .values().iterator();
1008:
1009:                while (listIterator.hasNext()) {
1010:                    List<JParameterizedType> list = listIterator.next();
1011:                    Iterator<JParameterizedType> typeIterator = list.iterator();
1012:                    while (typeIterator.hasNext()) {
1013:                        JType type = typeIterator.next();
1014:                        if (isInvalidatedTypeRecursive(type, invalidTypes)) {
1015:                            typeIterator.remove();
1016:                        }
1017:                    }
1018:                }
1019:            }
1020:
1021:            /**
1022:             * Removes the specified types from the type oracle.
1023:             * 
1024:             * @param invalidTypes set of types to remove
1025:             */
1026:            private void removeTypes(Set<JClassType> invalidTypes) {
1027:                Iterator<JClassType> iter = invalidTypes.iterator();
1028:
1029:                while (iter.hasNext()) {
1030:                    JClassType classType = iter.next();
1031:                    JPackage pkg = classType.getPackage();
1032:                    if (pkg != null) {
1033:                        pkg.remove(classType);
1034:                    }
1035:
1036:                    classType.removeFromSupertypes();
1037:                }
1038:            }
1039:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.