Source Code Cross Referenced for Type.java in  » Template-Engine » Tea » com » go » tea » compiler » 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 » Template Engine » Tea » com.go.tea.compiler 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* ====================================================================
0002:         * Tea - Copyright (c) 1997-2000 Walt Disney Internet Group
0003:         * ====================================================================
0004:         * The Tea Software License, Version 1.1
0005:         *
0006:         * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
0007:         *
0008:         * Redistribution and use in source and binary forms, with or without
0009:         * modification, are permitted provided that the following conditions
0010:         * are met:
0011:         *
0012:         * 1. Redistributions of source code must retain the above copyright
0013:         *    notice, this list of conditions and the following disclaimer.
0014:         *
0015:         * 2. Redistributions in binary form must reproduce the above copyright
0016:         *    notice, this list of conditions and the following disclaimer in
0017:         *    the documentation and/or other materials provided with the
0018:         *    distribution.
0019:         *
0020:         * 3. The end-user documentation included with the redistribution,
0021:         *    if any, must include the following acknowledgment:
0022:         *       "This product includes software developed by the
0023:         *        Walt Disney Internet Group (http://opensource.go.com/)."
0024:         *    Alternately, this acknowledgment may appear in the software itself,
0025:         *    if and wherever such third-party acknowledgments normally appear.
0026:         *
0027:         * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
0028:         *    not be used to endorse or promote products derived from this
0029:         *    software without prior written permission. For written
0030:         *    permission, please contact opensource@dig.com.
0031:         *
0032:         * 5. Products derived from this software may not be called "Tea",
0033:         *    "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
0034:         *    "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
0035:         *    written permission of the Walt Disney Internet Group.
0036:         *
0037:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0038:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0039:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0040:         * DISCLAIMED.  IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
0041:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0042:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0043:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
0044:         * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
0045:         * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
0046:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0047:         * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0048:         * ====================================================================
0049:         *
0050:         * For more information about Tea, please see http://opensource.go.com/.
0051:         */
0052:
0053:        package com.go.tea.compiler;
0054:
0055:        import java.lang.reflect.Array;
0056:        import java.lang.reflect.Field;
0057:        import java.lang.reflect.Modifier;
0058:        import java.lang.reflect.Method;
0059:        import java.util.Collection;
0060:        import java.util.List;
0061:        import java.util.Map;
0062:        import java.util.Set;
0063:        import java.util.HashSet;
0064:        import java.util.Iterator;
0065:        import java.beans.IntrospectionException;
0066:        import com.go.tea.util.BeanAnalyzer;
0067:        import com.go.tea.util.KeyedPropertyDescriptor;
0068:
0069:        /******************************************************************************
0070:         * Immutable representation of an expression's type.
0071:         *
0072:         * @author Brian S O'Neill
0073:         * @version
0074:         * <!--$$Revision:--> 45 <!-- $-->, <!--$$JustDate:--> 01/02/05 <!-- $-->
0075:         * @see com.go.tea.parsetree.Expression
0076:         */
0077:        public class Type implements  java.io.Serializable {
0078:            /** Type that is compatble with all other types */
0079:            public static final Type NULL_TYPE = new Type(Object.class) {
0080:                public String getSimpleName() {
0081:                    return toString();
0082:                }
0083:
0084:                public String getFullName() {
0085:                    return toString();
0086:                }
0087:
0088:                public String toString() {
0089:                    return "null-type";
0090:                }
0091:            };
0092:
0093:            /** Type that represents void, provided as a convenience */
0094:            public static final Type VOID_TYPE = new Type(void.class);
0095:
0096:            /** Type that represents all objects, provided as a convenience */
0097:            public static final Type OBJECT_TYPE = new Type(Object.class);
0098:
0099:            /** Type for representing ints, provided as a convenience */
0100:            public static final Type INT_TYPE = new Type(int.class);
0101:
0102:            /** Type for representing longs, provided as a convenience */
0103:            public static final Type LONG_TYPE = new Type(long.class);
0104:
0105:            /** Type for representing booleans, provided as a convenience */
0106:            public static final Type BOOLEAN_TYPE = new Type(boolean.class);
0107:
0108:            /** Type for representing Strings, provided as a convenience */
0109:            public static final Type STRING_TYPE = new Type(String.class);
0110:
0111:            /** Type for representing non-null Strings, provided as a convenience */
0112:            public static final Type NON_NULL_STRING_TYPE = STRING_TYPE
0113:                    .toNonNull();
0114:
0115:            private static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
0116:
0117:            private final Class mObjectClass;
0118:            private final Class mNaturalClass;
0119:            private final boolean mPrimitive;
0120:
0121:            private transient boolean mCheckedForArrayLookup;
0122:            private transient Type mArrayElementType;
0123:            private transient Type[] mArrayIndexTypes;
0124:            private transient Method[] mArrayAccessMethods;
0125:            private transient boolean mCheckedForIteration;
0126:            private transient Type mIterationElementType;
0127:
0128:            public Type(Class type) {
0129:                if (type.isPrimitive()) {
0130:                    mNaturalClass = type;
0131:                    mObjectClass = convertToObject(type);
0132:                    mPrimitive = true;
0133:                } else {
0134:                    mObjectClass = mNaturalClass = type;
0135:                    mPrimitive = false;
0136:                }
0137:            }
0138:
0139:            private Type(Class object, Class natural) {
0140:                mObjectClass = object;
0141:                mNaturalClass = natural;
0142:                if (natural.isPrimitive()) {
0143:                    mPrimitive = true;
0144:                } else {
0145:                    mPrimitive = false;
0146:                }
0147:            }
0148:
0149:            Type(Type type) {
0150:                mObjectClass = type.mObjectClass;
0151:                mNaturalClass = type.mNaturalClass;
0152:                mPrimitive = type.mPrimitive;
0153:
0154:                mCheckedForArrayLookup = type.mCheckedForArrayLookup;
0155:                mArrayElementType = type.mArrayElementType;
0156:                mArrayIndexTypes = type.mArrayIndexTypes;
0157:                mArrayAccessMethods = type.mArrayAccessMethods;
0158:                mCheckedForIteration = type.mCheckedForIteration;
0159:                mIterationElementType = type.mIterationElementType;
0160:            }
0161:
0162:            /**
0163:             * Class returned never represents a primitive type.
0164:             */
0165:            public Class getObjectClass() {
0166:                return mObjectClass;
0167:            }
0168:
0169:            /**
0170:             * Returns the natural class for this type. If type is primitive, then its
0171:             * primitive peer is returned.
0172:             */
0173:            public Class getNaturalClass() {
0174:                return mNaturalClass;
0175:            }
0176:
0177:            /**
0178:             * Returns true if this type is a primitive.
0179:             */
0180:            public boolean isPrimitive() {
0181:                return mPrimitive;
0182:            }
0183:
0184:            /**
0185:             * Returns true if this type is not primitive, but it has a primitive 
0186:             * type peer.
0187:             */
0188:            public boolean hasPrimitivePeer() {
0189:                if (mObjectClass == Integer.class
0190:                        || mObjectClass == Boolean.class
0191:                        || mObjectClass == Byte.class
0192:                        || mObjectClass == Character.class
0193:                        || mObjectClass == Short.class
0194:                        || mObjectClass == Long.class
0195:                        || mObjectClass == Float.class
0196:                        || mObjectClass == Double.class
0197:                        || mObjectClass == Void.class) {
0198:
0199:                    return true;
0200:                }
0201:
0202:                return false;
0203:            }
0204:
0205:            /**
0206:             * Returns a new type from this one that represents a primitive type.
0207:             * If this type cannot be represented by a primitive, then this is
0208:             * returned.
0209:             */
0210:            public Type toPrimitive() {
0211:                if (mPrimitive) {
0212:                    return this ;
0213:                } else {
0214:                    return new Type(mObjectClass,
0215:                            convertToPrimitive(mObjectClass));
0216:                }
0217:            }
0218:
0219:            /**
0220:             * Returns a new type from this one that represents a non-primitive type.
0221:             * If this type actually is primitive, the returned type is marked as not
0222:             * being able to reference null. i.e. if this type is int,
0223:             * new Type(Integer.class).toNonNull() is returned.
0224:             */
0225:            public Type toNonPrimitive() {
0226:                if (mPrimitive) {
0227:                    return new Type(mObjectClass).toNonNull();
0228:                } else {
0229:                    return this ;
0230:                }
0231:            }
0232:
0233:            /**
0234:             * Returns true if this type cannot reference null. For primitive types,
0235:             * true is always returned.
0236:             */
0237:            public boolean isNonNull() {
0238:                return isPrimitive();
0239:            }
0240:
0241:            /**
0242:             * Returns true if this type can reference null, or simply the opposite
0243:             * result of isNonNull.
0244:             */
0245:            public boolean isNullable() {
0246:                return !isNonNull();
0247:            }
0248:
0249:            /**
0250:             * Returns this type converted such that it cannot reference null.
0251:             */
0252:            public Type toNonNull() {
0253:                if (isNonNull()) {
0254:                    return this ;
0255:                } else {
0256:                    return new Type(this ) {
0257:                        public boolean isNonNull() {
0258:                            return true;
0259:                        }
0260:
0261:                        public boolean isNullable() {
0262:                            return false;
0263:                        }
0264:
0265:                        public Type toNullable() {
0266:                            return Type.this ;
0267:                        }
0268:                    };
0269:                }
0270:            }
0271:
0272:            /**
0273:             * Returns this type converted such that it can reference null. The
0274:             * resulting type is never primitive.
0275:             */
0276:            public Type toNullable() {
0277:                if (!isNonNull()) {
0278:                    return this ;
0279:                } else {
0280:                    return new Type(mObjectClass);
0281:                }
0282:            }
0283:
0284:            /**
0285:             * If this Type supports array lookup, then return the element type.
0286:             * Otherwise, null is returned.
0287:             */
0288:            public Type getArrayElementType() throws IntrospectionException {
0289:                if (!mCheckedForArrayLookup) {
0290:                    checkForArrayLookup();
0291:                }
0292:
0293:                return mArrayElementType;
0294:            }
0295:
0296:            /**
0297:             * If this Type supports array lookup, then return the index type. Because
0298:             * the index type may be overloaded, an array is returned.
0299:             * Null is returned if this Type doesn't support array lookup.
0300:             */
0301:            public Type[] getArrayIndexTypes() throws IntrospectionException {
0302:                if (!mCheckedForArrayLookup) {
0303:                    checkForArrayLookup();
0304:                }
0305:
0306:                return mArrayIndexTypes == null ? null
0307:                        : (Type[]) mArrayIndexTypes.clone();
0308:            }
0309:
0310:            /**
0311:             * If this Type supports array lookup, then return all of the methods
0312:             * that can be called to access the array. If there are no methods, then
0313:             * an empty array is returned. Null is returned only if this Type
0314:             * doesn't support array lookup.
0315:             */
0316:            public Method[] getArrayAccessMethods()
0317:                    throws IntrospectionException {
0318:                if (!mCheckedForArrayLookup) {
0319:                    checkForArrayLookup();
0320:                }
0321:
0322:                return mArrayAccessMethods == null ? null
0323:                        : (Method[]) mArrayAccessMethods.clone();
0324:            }
0325:
0326:            /**
0327:             * If this type supports iteration, then the element type is returned.
0328:             * Otherwise, null is returned.
0329:             */
0330:            public Type getIterationElementType() throws IntrospectionException {
0331:                if (!mCheckedForIteration) {
0332:                    mCheckedForIteration = true;
0333:
0334:                    if (mNaturalClass.isArray()) {
0335:                        mIterationElementType = getArrayElementType();
0336:                    } else if (Collection.class.isAssignableFrom(mNaturalClass)) {
0337:                        mIterationElementType = OBJECT_TYPE;
0338:
0339:                        try {
0340:                            Field field = mNaturalClass
0341:                                    .getField(BeanAnalyzer.ELEMENT_TYPE_FIELD_NAME);
0342:                            if (field.getType() == Class.class
0343:                                    && Modifier.isStatic(field.getModifiers())) {
0344:
0345:                                mIterationElementType = new Type((Class) field
0346:                                        .get(null));
0347:                            }
0348:                        } catch (NoSuchFieldException e) {
0349:                        } catch (IllegalAccessException e) {
0350:                        }
0351:                    }
0352:                }
0353:
0354:                return mIterationElementType;
0355:            }
0356:
0357:            /**
0358:             * Returns true if this type supports iteration in the reverse direction.
0359:             */
0360:            public boolean isReverseIterationSupported() {
0361:                return mNaturalClass.isArray()
0362:                        || List.class.isAssignableFrom(mNaturalClass);
0363:            }
0364:
0365:            private void checkForArrayLookup() throws IntrospectionException {
0366:                mCheckedForArrayLookup = true;
0367:
0368:                if (mObjectClass.isArray()) {
0369:                    mArrayElementType = new Type(mObjectClass
0370:                            .getComponentType());
0371:                    mArrayAccessMethods = EMPTY_METHOD_ARRAY;
0372:                    mArrayIndexTypes = new Type[] { INT_TYPE };
0373:                    return;
0374:                }
0375:
0376:                try {
0377:                    Map properties = BeanAnalyzer
0378:                            .getAllProperties(mObjectClass);
0379:
0380:                    KeyedPropertyDescriptor keyed = (KeyedPropertyDescriptor) properties
0381:                            .get(BeanAnalyzer.KEYED_PROPERTY_NAME);
0382:
0383:                    if (keyed == null) {
0384:                        return;
0385:                    }
0386:
0387:                    mArrayElementType = new Type(keyed.getKeyedPropertyType());
0388:                    mArrayAccessMethods = keyed.getKeyedReadMethods();
0389:                } catch (ClassCastException e) {
0390:                    return;
0391:                }
0392:
0393:                int length = mArrayAccessMethods.length;
0394:                mArrayIndexTypes = new Type[length];
0395:                for (int i = 0; i < length; i++) {
0396:                    Method m = mArrayAccessMethods[i];
0397:                    mArrayIndexTypes[i] = new Type(m.getReturnType());
0398:                }
0399:            }
0400:
0401:            /**
0402:             * Accessed by the TypeChecker, to override the default.
0403:             */
0404:            Type setArrayElementType(Type elementType)
0405:                    throws IntrospectionException {
0406:                Type type = new Type(mObjectClass, mNaturalClass);
0407:                type.checkForArrayLookup();
0408:                type.mArrayElementType = elementType;
0409:                return type;
0410:            }
0411:
0412:            public String getSimpleName() {
0413:                if (mNaturalClass.isArray()) {
0414:                    int dim = 0;
0415:                    Class baseNat = mNaturalClass;
0416:                    Type baseType = this ;
0417:                    while (baseNat.isArray()) {
0418:                        dim++;
0419:                        baseNat = baseNat.getComponentType();
0420:                        try {
0421:                            baseType = baseType.getArrayElementType();
0422:                        } catch (IntrospectionException e) {
0423:                            baseType = new Type(baseNat);
0424:                        }
0425:                    }
0426:
0427:                    String baseName = baseType.getSimpleName();
0428:                    StringBuffer nameBuf = new StringBuffer(baseName.length()
0429:                            + dim * 2);
0430:                    nameBuf.append(baseName);
0431:
0432:                    while (dim-- > 0) {
0433:                        nameBuf.append('[');
0434:                        nameBuf.append(']');
0435:                    }
0436:
0437:                    return nameBuf.toString();
0438:                } else if (mPrimitive) {
0439:                    return mNaturalClass.getName();
0440:                } else {
0441:                    String name = mObjectClass.getName();
0442:                    int index = name.lastIndexOf('.');
0443:                    if (index >= 0) {
0444:                        name = name.substring(index + 1);
0445:                    }
0446:                    return name;
0447:                }
0448:            }
0449:
0450:            public String getFullName() {
0451:                if (isPrimitive()) {
0452:                    return mNaturalClass.getName();
0453:                }
0454:
0455:                StringBuffer nameBuf = new StringBuffer(20);
0456:                if (isNonNull()) {
0457:                    nameBuf.append("non-null ");
0458:                }
0459:
0460:                if (!mNaturalClass.isArray()) {
0461:                    nameBuf.append(mObjectClass.getName());
0462:                } else {
0463:                    int dim = 0;
0464:                    Class baseNat = mNaturalClass;
0465:                    Type baseType = this ;
0466:                    while (baseNat.isArray()) {
0467:                        dim++;
0468:                        baseNat = baseNat.getComponentType();
0469:                        try {
0470:                            baseType = baseType.getArrayElementType();
0471:                        } catch (IntrospectionException e) {
0472:                            baseType = new Type(baseNat);
0473:                        }
0474:                    }
0475:
0476:                    String baseName = baseType.getFullName();
0477:                    nameBuf.append(baseName);
0478:
0479:                    while (dim-- > 0) {
0480:                        nameBuf.append('[');
0481:                        nameBuf.append(']');
0482:                    }
0483:                }
0484:
0485:                return nameBuf.toString();
0486:            }
0487:
0488:            public String toString() {
0489:                if (!isPrimitive() && isNonNull()) {
0490:                    return "non-null " + mNaturalClass.getName();
0491:                } else {
0492:                    return mNaturalClass.getName();
0493:                }
0494:            }
0495:
0496:            public int hashCode() {
0497:                return mNaturalClass.hashCode();
0498:            }
0499:
0500:            public boolean equals(Object another) {
0501:                if (this  == another) {
0502:                    return true;
0503:                }
0504:
0505:                if (another instanceof  Type) {
0506:                    Type t = (Type) another;
0507:
0508:                    if (this  == NULL_TYPE || another == NULL_TYPE) {
0509:                        return false;
0510:                    }
0511:
0512:                    if (mNaturalClass == t.mNaturalClass
0513:                            && isNonNull() == t.isNonNull()) {
0514:
0515:                        if (!mCheckedForArrayLookup
0516:                                && !t.mCheckedForArrayLookup) {
0517:                            // Don't recursively check array element type. They
0518:                            // will be the same. This test fixes an infinite recursion
0519:                            // bug if the element type is of the same type.
0520:                            return true;
0521:                        }
0522:
0523:                        try {
0524:                            Type this ArrayType = getArrayElementType();
0525:                            Type otherArrayType = t.getArrayElementType();
0526:
0527:                            if (this ArrayType != null) {
0528:                                if (this ArrayType.equals(otherArrayType)) {
0529:                                    return true;
0530:                                }
0531:                            } else {
0532:                                if (otherArrayType == null) {
0533:                                    return true;
0534:                                }
0535:                            }
0536:                        } catch (IntrospectionException e) {
0537:                        }
0538:                    }
0539:                }
0540:
0541:                return false;
0542:            }
0543:
0544:            /**
0545:             * Returns a type that is compatible with this type, and the one passed in.
0546:             * The type returned is selected using a best-fit algorithm.
0547:             *
0548:             * <p>If the type passed in represents a primitive type, but this type is
0549:             * not, the type returned is an object (or a subclass of), but never a 
0550:             * primitive type. Compatible primitive types are returned when both this
0551:             * and the parameter type were already primitive types.
0552:             *
0553:             * <p>Input types which are arrays are also supported by this method.
0554:             *
0555:             * <p>Returns null if the given type isn't compatible with this one.
0556:             */
0557:            public Type getCompatibleType(Type other) {
0558:                if (other == null) {
0559:                    return null;
0560:                }
0561:
0562:                if (equals(other)) {
0563:                    if (this  == NULL_TYPE) {
0564:                        return other;
0565:                    } else {
0566:                        return this ;
0567:                    }
0568:                }
0569:
0570:                Class classA = mObjectClass;
0571:                Class classB = other.mObjectClass;
0572:
0573:                Type compat;
0574:
0575:                if (classA == Void.class) {
0576:                    if (classB == Void.class) {
0577:                        compat = this ;
0578:                    } else {
0579:                        return null;
0580:                    }
0581:                } else if (classB == Void.class) {
0582:                    return null;
0583:                } else if (other == NULL_TYPE) {
0584:                    compat = this .toNullable();
0585:                } else if (this  == NULL_TYPE) {
0586:                    compat = other.toNullable();
0587:                } else if (Number.class.isAssignableFrom(classA)
0588:                        && Number.class.isAssignableFrom(classB)) {
0589:
0590:                    Class clazz = compatibleNumber(classA, classB);
0591:                    if (isPrimitive() && other.isPrimitive()) {
0592:                        compat = new Type(clazz, convertToPrimitive(clazz));
0593:                    } else {
0594:                        compat = new Type(clazz);
0595:                    }
0596:                } else {
0597:                    compat = new Type(findCommonBaseClass(classA, classB));
0598:                }
0599:
0600:                if (isNonNull() && other.isNonNull()) {
0601:                    compat = compat.toNonNull();
0602:                }
0603:
0604:                return compat;
0605:            }
0606:
0607:            /**
0608:             * Returns the most specific common superclass or interface that can be 
0609:             * used to represent both of the specified classes. Null is only returned
0610:             * if either class refers to a primitive type and isn't the same as the 
0611:             * other class.
0612:             */
0613:            public static Class findCommonBaseClass(Class a, Class b) {
0614:                Class clazz = findCommonBaseClass0(a, b);
0615:
0616:                if (clazz != null && clazz.isInterface()) {
0617:                    // Only return interface if it actually defines something.
0618:                    if (clazz.getMethods().length <= 0) {
0619:                        //clazz = Object.class;
0620:                    }
0621:                }
0622:
0623:                return clazz;
0624:            }
0625:
0626:            private static Class findCommonBaseClass0(Class a, Class b) {
0627:                if (a == b) {
0628:                    return a;
0629:                }
0630:
0631:                if (a.isPrimitive() || b.isPrimitive()) {
0632:                    return null;
0633:                }
0634:
0635:                if (a.isArray() && b.isArray()) {
0636:                    Class clazz = findCommonBaseClass(a.getComponentType(), b
0637:                            .getComponentType());
0638:
0639:                    if (clazz == null) {
0640:                        return Object.class;
0641:                    }
0642:
0643:                    return Array.newInstance(clazz, 0).getClass();
0644:                }
0645:
0646:                // Determine the intersection set of all the classes, superclasses and 
0647:                // interfaces from the passed in classes.
0648:                Set set = new HashSet(19);
0649:                addToClassSet(set, a);
0650:
0651:                Set setB = new HashSet(19);
0652:                addToClassSet(setB, b);
0653:
0654:                set.retainAll(setB);
0655:
0656:                int size = set.size();
0657:                if (size == 1) {
0658:                    return (Class) set.iterator().next();
0659:                } else if (size == 0) {
0660:                    return Object.class;
0661:                }
0662:
0663:                // Reduce the set by removing classes/interfaces that are extended and
0664:                // interfaces that are implemented by other classes.
0665:                Iterator i = set.iterator();
0666:                while (i.hasNext()) {
0667:                    Class x = (Class) i.next();
0668:                    Iterator j = set.iterator();
0669:                    while (j.hasNext()) {
0670:                        Class y = (Class) j.next();
0671:                        if (x != y && x.isAssignableFrom(y)) {
0672:                            i.remove();
0673:                            break;
0674:                        }
0675:                    }
0676:                }
0677:
0678:                size = set.size();
0679:                if (size == 1) {
0680:                    return (Class) set.iterator().next();
0681:                } else if (size == 0) {
0682:                    return Object.class;
0683:                }
0684:
0685:                // Reduce the set by discarding interfaces.
0686:                i = set.iterator();
0687:                while (i.hasNext()) {
0688:                    if (((Class) i.next()).isInterface()) {
0689:                        i.remove();
0690:                    }
0691:                }
0692:
0693:                if (set.size() == 1) {
0694:                    return (Class) set.iterator().next();
0695:                }
0696:
0697:                return Object.class;
0698:            }
0699:
0700:            private static void addToClassSet(Set set, Class clazz) {
0701:                if (clazz == null || !set.add(clazz)) {
0702:                    return;
0703:                }
0704:
0705:                addToClassSet(set, clazz.getSuperclass());
0706:
0707:                Class[] interfaces = clazz.getInterfaces();
0708:                for (int i = 0; i < interfaces.length; i++) {
0709:                    addToClassSet(set, interfaces[i]);
0710:                }
0711:            }
0712:
0713:            private static Class compatibleNumber(Class classA, Class classB) {
0714:                if (classA == Integer.class) {
0715:
0716:                    if (classB == Integer.class || classB == Byte.class
0717:                            || classB == Short.class) {
0718:
0719:                        return Integer.class;
0720:                    }
0721:
0722:                    if (classB == Long.class) {
0723:                        return classB;
0724:                    }
0725:                } else if (classA == Byte.class || classA == Short.class) {
0726:                    if (classB == Integer.class || classB == Byte.class
0727:                            || classB == Short.class) {
0728:
0729:                        return Integer.class;
0730:                    }
0731:
0732:                    if (classB == Long.class) {
0733:                        return classB;
0734:                    }
0735:
0736:                    if (classB == Float.class) {
0737:                        return Float.class;
0738:                    }
0739:                } else if (classA == Float.class) {
0740:                    if (classB == Float.class) {
0741:                        return classB;
0742:                    }
0743:
0744:                    if (classB == Byte.class || classB == Short.class) {
0745:                        return Float.class;
0746:                    }
0747:                } else if (classA == Long.class) {
0748:                    if (classB == Integer.class || classB == Byte.class
0749:                            || classB == Short.class || classB == Long.class) {
0750:
0751:                        return Long.class;
0752:                    }
0753:                }
0754:
0755:                return Double.class;
0756:            }
0757:
0758:            /**
0759:             * If class passed in represents a primitive type, its object peer is
0760:             * returned. Otherwise, it is returned unchanged.
0761:             */
0762:            private static Class convertToObject(Class type) {
0763:                if (type == int.class) {
0764:                    return Integer.class;
0765:                } else if (type == boolean.class) {
0766:                    return Boolean.class;
0767:                } else if (type == byte.class) {
0768:                    return Byte.class;
0769:                } else if (type == char.class) {
0770:                    return Character.class;
0771:                } else if (type == short.class) {
0772:                    return Short.class;
0773:                } else if (type == long.class) {
0774:                    return Long.class;
0775:                } else if (type == float.class) {
0776:                    return Float.class;
0777:                } else if (type == double.class) {
0778:                    return Double.class;
0779:                } else if (type == void.class) {
0780:                    return Void.class;
0781:                } else {
0782:                    return type;
0783:                }
0784:            }
0785:
0786:            /**
0787:             * If class passed in has a primitive type peer, it is returned.
0788:             * Otherwise, it is returned unchanged.
0789:             */
0790:            private static Class convertToPrimitive(Class type) {
0791:                if (type == Integer.class) {
0792:                    return int.class;
0793:                } else if (type == Boolean.class) {
0794:                    return boolean.class;
0795:                } else if (type == Byte.class) {
0796:                    return byte.class;
0797:                } else if (type == Character.class) {
0798:                    return char.class;
0799:                } else if (type == Short.class) {
0800:                    return short.class;
0801:                } else if (type == Long.class) {
0802:                    return long.class;
0803:                } else if (type == Float.class) {
0804:                    return float.class;
0805:                } else if (type == Double.class) {
0806:                    return double.class;
0807:                } else if (type == Void.class) {
0808:                    return void.class;
0809:                } else {
0810:                    return type;
0811:                }
0812:            }
0813:
0814:            /**
0815:             * Returns the conversion cost of assigning the given type to this type.
0816:             * Conversions are allowed between arrays as well if they have the
0817:             * same dimensions. If no legal conversion exists, -1 is returned. 
0818:             * The conversion costs are as follows:
0819:             * 
0820:             * <ol>
0821:             * <li>any type is assignable by its own type
0822:             * <li>any superclass type is assignable by a subclass type
0823:             * <li>any object with a primitive peer can be converted to its primitive
0824:             * <li>any primitive can be converted to its object peer
0825:             * <li>any byte or short can be widened to an int
0826:             * <li>any byte, short or int can be widened to a long
0827:             * <li>any byte or short can be widened to a float
0828:             * <li>any primitive number can be widened to a double
0829:             * <li>any Number object can be converted to a primitive and widened
0830:             * <li>any primitive number can be converted to a Number object
0831:             * <li>any primitive number can be widened to a Number object
0832:             * <li>any Number object can be widened to another Number object
0833:             * <li>any primitive number can be narrowed to a double
0834:             * <li>any Number object can be narrowed to a double
0835:             * <li>any primitive number can be narrowed to a Double object
0836:             * <li>any Number object can be narrowed to a Double object
0837:             * <li>any primitive number can be narrowed to a long
0838:             * <li>any Number object can be narrowed to a long
0839:             * <li>any primitive number can be narrowed to a Long object
0840:             * <li>any Number object can be narrowed to a Long object
0841:             * <li>any primitive number can be narrowed to a float
0842:             * <li>any Number object can be narrowed to a float
0843:             * <li>any primitive number can be narrowed to a Float object
0844:             * <li>any Number object can be narrowed to a Float object
0845:             * <li>any primitive number can be narrowed to a int
0846:             * <li>any Number object can be narrowed to a int
0847:             * <li>any primitive number can be narrowed to a Integer object
0848:             * <li>any Number object can be narrowed to a Integer object
0849:             * <li>any primitive number can be narrowed to a short
0850:             * <li>any Number object can be narrowed to a short
0851:             * <li>any primitive number can be narrowed to a Short object
0852:             * <li>any Number object can be narrowed to a Short object
0853:             * <li>any primitive number can be narrowed to a byte
0854:             * <li>any Number object can be narrowed to a byte
0855:             * <li>any primitive number can be narrowed to a Byte object
0856:             * <li>any Number object can be narrowed to a Byte object
0857:             * <li>any primitive can be converted to an object
0858:             * <li>NULL_TYPE can be converted to any object
0859:             * <li>anything can be converted to a String
0860:             * </ol>
0861:             *
0862:             * @return the conversion cost, or -1 if the other can't assign to this
0863:             */
0864:            public int convertableFrom(Type other) {
0865:                if (equals(other)) {
0866:                    return 1;
0867:                }
0868:
0869:                Class this Nat = mNaturalClass;
0870:                Class otherNat = other.mNaturalClass;
0871:
0872:                if (this Nat.isAssignableFrom(otherNat)) {
0873:                    return 2;
0874:                }
0875:
0876:                if (other == NULL_TYPE && !this Nat.isPrimitive()) {
0877:                    return 38;
0878:                }
0879:
0880:                if (this Nat.isArray() && otherNat.isArray()) {
0881:                    // Get dimensions of each array.
0882:                    int this Dim = 0;
0883:                    while (this Nat.isArray()) {
0884:                        this Dim++;
0885:                        this Nat = this Nat.getComponentType();
0886:                    }
0887:
0888:                    int otherDim = 0;
0889:                    while (otherNat.isArray()) {
0890:                        otherDim++;
0891:                        otherNat = otherNat.getComponentType();
0892:                    }
0893:
0894:                    if (this Dim != otherDim) {
0895:                        return -1;
0896:                    }
0897:                }
0898:
0899:                int aCode = typeCode(this Nat);
0900:                if (aCode < 0) {
0901:                    return -1;
0902:                }
0903:                int bCode = typeCode(otherNat);
0904:                if (bCode < 0) {
0905:                    if (aCode == 18) {
0906:                        // Anything can be converted to a String.
0907:                        return 39;
0908:                    } else {
0909:                        return -1;
0910:                    }
0911:                }
0912:
0913:                return mCostTable[bCode][aCode];
0914:            }
0915:
0916:            private static int typeCode(Class clazz) {
0917:                if (clazz.isPrimitive()) {
0918:                    if (clazz == boolean.class) {
0919:                        return 0;
0920:                    } else if (clazz == char.class) {
0921:                        return 1;
0922:                    } else if (clazz == byte.class) {
0923:                        return 2;
0924:                    } else if (clazz == short.class) {
0925:                        return 3;
0926:                    } else if (clazz == int.class) {
0927:                        return 4;
0928:                    } else if (clazz == float.class) {
0929:                        return 5;
0930:                    } else if (clazz == long.class) {
0931:                        return 6;
0932:                    } else if (clazz == double.class) {
0933:                        return 7;
0934:                    }
0935:                } else {
0936:                    if (clazz == Boolean.class) {
0937:                        return 8;
0938:                    } else if (clazz == Character.class) {
0939:                        return 9;
0940:                    } else if (clazz == Byte.class) {
0941:                        return 10;
0942:                    } else if (clazz == Short.class) {
0943:                        return 11;
0944:                    } else if (clazz == Integer.class) {
0945:                        return 12;
0946:                    } else if (clazz == Float.class) {
0947:                        return 13;
0948:                    } else if (clazz == Long.class) {
0949:                        return 14;
0950:                    } else if (clazz == Double.class) {
0951:                        return 15;
0952:                    } else if (Number.class.isAssignableFrom(clazz)) {
0953:                        return 16;
0954:                    } else if (clazz == Object.class) {
0955:                        return 17;
0956:                    } else if (clazz == String.class) {
0957:                        return 18;
0958:                    }
0959:                }
0960:
0961:                return -1;
0962:            }
0963:
0964:            // 19 by 19 two dimensional byte array. [from][to]
0965:            private static byte[][] mCostTable = {
0966:                    //0  1   2  3  4  5  6  7   8  9  10 11 12 13 14 15  16  17 18        
0967:
0968:                    { 1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1,
0969:                            -1, -1, 37, 39 }, //  0
0970:                    { -1, 1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1,
0971:                            -1, -1, 37, 39 }, //  1
0972:
0973:                    { -1, -1, 1, 5, 5, 7, 6, 8, -1, -1, 4, 11, 11, 11, 11, 11,
0974:                            10, 37, 39 }, //  2
0975:                    { -1, -1, 33, 1, 5, 7, 6, 8, -1, -1, 35, 4, 11, 11, 11, 11,
0976:                            10, 37, 39 }, //  3
0977:                    { -1, -1, 33, 29, 1, 21, 6, 8, -1, -1, 35, 31, 4, 23, 11,
0978:                            11, 10, 37, 39 }, //  4
0979:                    { -1, -1, 33, 29, 25, 1, 17, 8, -1, -1, 35, 31, 27, 4, 19,
0980:                            11, 10, 37, 39 }, //  5
0981:                    { -1, -1, 33, 29, 25, 21, 1, 13, -1, -1, 35, 31, 27, 23, 4,
0982:                            15, 10, 37, 39 }, //  6
0983:                    { -1, -1, 33, 29, 25, 21, 17, 1, -1, -1, 35, 31, 27, 23,
0984:                            19, 4, 10, 37, 39 }, //  7
0985:
0986:                    { 3, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1,
0987:                            -1, -1, 2, 39 }, //  8
0988:                    { -1, 3, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1,
0989:                            -1, -1, 2, 39 }, //  9
0990:
0991:                    { -1, -1, 3, 9, 9, 9, 9, 9, -1, -1, 1, 12, 12, 12, 12, 12,
0992:                            2, 2, 39 }, // 10
0993:                    { -1, -1, 34, 3, 9, 9, 9, 9, -1, -1, 36, 1, 12, 12, 12, 12,
0994:                            2, 2, 39 }, // 11
0995:                    { -1, -1, 34, 30, 3, 22, 9, 9, -1, -1, 36, 32, 1, 24, 12,
0996:                            12, 2, 2, 39 }, // 12
0997:                    { -1, -1, 34, 30, 26, 3, 18, 9, -1, -1, 36, 32, 28, 1, 20,
0998:                            12, 2, 2, 39 }, // 13
0999:                    { -1, -1, 34, 30, 26, 22, 3, 14, -1, -1, 36, 32, 28, 24, 1,
1000:                            16, 2, 2, 39 }, // 14
1001:                    { -1, -1, 34, 30, 26, 22, 18, 3, -1, -1, 36, 32, 28, 24,
1002:                            20, 1, 2, 2, 39 }, // 15
1003:
1004:                    { -1, -1, 34, 30, 26, 22, 18, 14, -1, -1, 36, 32, 28, 24,
1005:                            20, 16, 1, 2, 39 }, // 16
1006:
1007:                    { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1008:                            -1, -1, -1, 1, 39 }, // 17
1009:                    { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1010:                            -1, -1, -1, 2, 1 }, // 18
1011:                    { 66, 82, 73, 65, 78, 32, 83, 32, 79, 39, 78, 69, 73, 76,
1012:                            76, -1, -1, -1, -1 } // 19
1013:            };
1014:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.