Source Code Cross Referenced for MethodMap.java in  » Template-Engine » freemarker-2.3.10 » freemarker » ext » beans » 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 » freemarker 2.3.10 » freemarker.ext.beans 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright (c) 2003 The Visigoth Software Society. All rights
003:         * reserved.
004:         *
005:         * Redistribution and use in source and binary forms, with or without
006:         * modification, are permitted provided that the following conditions
007:         * are met:
008:         *
009:         * 1. Redistributions of source code must retain the above copyright
010:         *    notice, this list of conditions and the following disclaimer.
011:         *
012:         * 2. Redistributions in binary form must reproduce the above copyright
013:         *    notice, this list of conditions and the following disclaimer in
014:         *    the documentation and/or other materials provided with the
015:         *    distribution.
016:         *
017:         * 3. The end-user documentation included with the redistribution, if
018:         *    any, must include the following acknowledgement:
019:         *       "This product includes software developed by the
020:         *        Visigoth Software Society (http://www.visigoths.org/)."
021:         *    Alternately, this acknowledgement may appear in the software itself,
022:         *    if and wherever such third-party acknowledgements normally appear.
023:         *
024:         * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the 
025:         *    project contributors may be used to endorse or promote products derived
026:         *    from this software without prior written permission. For written
027:         *    permission, please contact visigoths@visigoths.org.
028:         *
029:         * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
030:         *    nor may "FreeMarker" or "Visigoth" appear in their names
031:         *    without prior written permission of the Visigoth Software Society.
032:         *
033:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
034:         * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
035:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
036:         * DISCLAIMED.  IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
037:         * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
038:         * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
039:         * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
040:         * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
041:         * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
042:         * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
043:         * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
044:         * SUCH DAMAGE.
045:         * ====================================================================
046:         *
047:         * This software consists of voluntary contributions made by many
048:         * individuals on behalf of the Visigoth Software Society. For more
049:         * information on the Visigoth Software Society, please see
050:         * http://www.visigoths.org/
051:         */
052:
053:        package freemarker.ext.beans;
054:
055:        import java.lang.reflect.AccessibleObject;
056:        import java.lang.reflect.Constructor;
057:        import java.lang.reflect.Method;
058:        import java.util.ArrayList;
059:        import java.util.HashMap;
060:        import java.util.HashSet;
061:        import java.util.Iterator;
062:        import java.util.LinkedList;
063:        import java.util.List;
064:        import java.util.Map;
065:        import java.util.Set;
066:
067:        import freemarker.template.TemplateModelException;
068:
069:        class MethodMap {
070:            private static final Class BIGDECIMAL_CLASS = java.math.BigDecimal.class;
071:            private static final Class NUMBER_CLASS = java.lang.Number.class;
072:
073:            private static final Object[] EMPTY_ARGS = new Object[0];
074:            private static final Class OBJECT_CLASS = java.lang.Object.class;
075:            private static final ClassString EMPTY_STRING = new ClassString(
076:                    EMPTY_ARGS);
077:
078:            private static final Object NO_SUCH_METHOD = new Object();
079:            private static final Object AMBIGUOUS_METHOD = new Object();
080:
081:            private final String name;
082:            // Cache of Class[] --> AccessibleObject. Maps the actual types involved in
083:            // a method/constructor call to the most specific method/constructor for 
084:            // those types
085:            private final Map selectorCache = new HashMap();
086:            private Class[][] unwrapTypes;
087:            private final List methods = new LinkedList();
088:
089:            MethodMap(String name) {
090:                this .name = name;
091:            }
092:
093:            void addMethod(Method method) {
094:                methods.add(method);
095:                updateUnwrapTypes(method.getParameterTypes());
096:            }
097:
098:            void addConstructor(Constructor constructor) {
099:                methods.add(constructor);
100:                updateUnwrapTypes(constructor.getParameterTypes());
101:            }
102:
103:            private void updateUnwrapTypes(Class[] argTypes) {
104:                int l = argTypes.length - 1;
105:                if (l == -1) {
106:                    return;
107:                }
108:                if (unwrapTypes == null) {
109:                    unwrapTypes = new Class[l + 1][];
110:                    unwrapTypes[l] = argTypes;
111:                } else if (unwrapTypes.length <= l) {
112:                    Class[][] newUnwrapTypes = new Class[l + 1][];
113:                    System.arraycopy(unwrapTypes, 0, newUnwrapTypes, 0,
114:                            unwrapTypes.length);
115:                    unwrapTypes = newUnwrapTypes;
116:                    unwrapTypes[l] = argTypes;
117:                } else {
118:                    Class[] oldTypes = unwrapTypes[l];
119:                    if (oldTypes == null) {
120:                        unwrapTypes[l] = argTypes;
121:                    } else {
122:                        for (int i = 0; i < oldTypes.length; ++i) {
123:                            oldTypes[i] = getMostSpecificCommonType(
124:                                    oldTypes[i], argTypes[i]);
125:                        }
126:                    }
127:                }
128:            }
129:
130:            String getName() {
131:                return name;
132:            }
133:
134:            Class[] getUnwrapTypes(List args) throws TemplateModelException {
135:                int l = args.size() - 1;
136:                if (l == -1) {
137:                    return EMPTY_STRING.getClasses();
138:                }
139:                if (l < unwrapTypes.length) {
140:                    Class[] retval = unwrapTypes[l];
141:                    if (retval != null) {
142:                        return retval;
143:                    }
144:                }
145:                throw new TemplateModelException("No signature of method "
146:                        + name + " accepts " + (l + 1) + " arguments");
147:            }
148:
149:            AccessibleObject getMostSpecific(final Object[] args)
150:                    throws TemplateModelException {
151:                ClassString cs = null;
152:                if (args == null) {
153:                    cs = EMPTY_STRING;
154:                } else {
155:                    cs = new ClassString(args);
156:                }
157:                synchronized (selectorCache) {
158:                    Object obj = selectorCache.get(cs);
159:                    if (obj == null) {
160:                        selectorCache
161:                                .put(cs, obj = cs.getMostSpecific(methods));
162:                    }
163:                    if (obj instanceof  AccessibleObject) {
164:                        return (AccessibleObject) obj;
165:                    }
166:                    if (obj == NO_SUCH_METHOD) {
167:                        throw new TemplateModelException(
168:                                "No signature of method " + name + " matches "
169:                                        + cs.listArgumentTypes());
170:                    } else {
171:                        // Can be only AMBIGUOUS_METHOD
172:                        throw new TemplateModelException(
173:                                "Multiple signatures of method " + name
174:                                        + " match " + cs.listArgumentTypes());
175:                    }
176:                }
177:            }
178:
179:            private static final class ClassString {
180:                private final Class[] classes;
181:
182:                ClassString(Object[] objects) {
183:                    int l = objects.length;
184:                    classes = new Class[l];
185:                    for (int i = 0; i < l; ++i) {
186:                        Object obj = objects[i];
187:                        classes[i] = obj == null ? OBJECT_CLASS : obj
188:                                .getClass();
189:                    }
190:                }
191:
192:                Class[] getClasses() {
193:                    return classes;
194:                }
195:
196:                public int hashCode() {
197:                    int hash = 0;
198:                    for (int i = 0; i < classes.length; ++i) {
199:                        hash ^= classes[i].hashCode();
200:                    }
201:                    return hash;
202:                }
203:
204:                public boolean equals(Object o) {
205:                    if (o instanceof  ClassString) {
206:                        ClassString cs = (ClassString) o;
207:                        if (cs.classes.length != classes.length) {
208:                            return false;
209:                        }
210:                        for (int i = 0; i < classes.length; ++i) {
211:                            if (cs.classes[i] != classes[i]) {
212:                                return false;
213:                            }
214:                        }
215:                        return true;
216:                    }
217:                    return false;
218:                }
219:
220:                private static final int MORE_SPECIFIC = 0;
221:                private static final int LESS_SPECIFIC = 1;
222:                private static final int INDETERMINATE = 2;
223:
224:                Object getMostSpecific(List methods) {
225:                    LinkedList applicables = getApplicables(methods);
226:                    if (applicables.isEmpty()) {
227:                        return NO_SUCH_METHOD;
228:                    }
229:                    if (applicables.size() == 1) {
230:                        return applicables.getFirst();
231:                    }
232:                    LinkedList maximals = new LinkedList();
233:                    for (Iterator applicable = applicables.iterator(); applicable
234:                            .hasNext();) {
235:                        Object objapp = applicable.next();
236:                        Class[] appArgs = getParameterTypes(objapp);
237:                        boolean lessSpecific = false;
238:                        for (Iterator maximal = maximals.iterator(); !lessSpecific
239:                                && maximal.hasNext();) {
240:                            Object max = maximal.next();
241:                            switch (moreSpecific(appArgs,
242:                                    getParameterTypes(max))) {
243:                            case MORE_SPECIFIC: {
244:                                maximal.remove();
245:                                break;
246:                            }
247:                            case LESS_SPECIFIC: {
248:                                lessSpecific = true;
249:                                break;
250:                            }
251:                            }
252:                        }
253:                        if (!lessSpecific) {
254:                            maximals.addLast(objapp);
255:                        }
256:                    }
257:                    if (maximals.size() > 1) {
258:                        return AMBIGUOUS_METHOD;
259:                    }
260:                    return maximals.getFirst();
261:                }
262:
263:                private static Class[] getParameterTypes(Object obj) {
264:                    if (obj instanceof  Method) {
265:                        return ((Method) obj).getParameterTypes();
266:                    }
267:                    if (obj instanceof  Constructor) {
268:                        return ((Constructor) obj).getParameterTypes();
269:                    }
270:                    // Cannot happen
271:                    throw new Error();
272:                }
273:
274:                private static int moreSpecific(Class[] c1, Class[] c2) {
275:                    boolean c1MoreSpecific = false;
276:                    boolean c2MoreSpecific = false;
277:                    for (int i = 0; i < c1.length; ++i) {
278:                        if (c1[i] != c2[i]) {
279:                            c1MoreSpecific = c1MoreSpecific
280:                                    || isMoreSpecific(c1[i], c2[i]);
281:                            c2MoreSpecific = c2MoreSpecific
282:                                    || isMoreSpecific(c2[i], c1[i]);
283:                        }
284:                    }
285:                    if (c1MoreSpecific) {
286:                        if (c2MoreSpecific) {
287:                            return INDETERMINATE;
288:                        }
289:                        return MORE_SPECIFIC;
290:                    }
291:                    if (c2MoreSpecific) {
292:                        return LESS_SPECIFIC;
293:                    }
294:                    return INDETERMINATE;
295:                }
296:
297:                /**
298:                 * Returns all methods that are applicable to actual
299:                 * parameter classes represented by this ClassString object.
300:                 */
301:                LinkedList getApplicables(List methods) {
302:                    LinkedList list = new LinkedList();
303:                    for (Iterator imethod = methods.iterator(); imethod
304:                            .hasNext();) {
305:                        Object method = imethod.next();
306:                        if (isApplicable(method)) {
307:                            list.add(method);
308:                        }
309:
310:                    }
311:                    return list;
312:                }
313:
314:                /**
315:                 * Returns true if the supplied method is applicable to actual
316:                 * parameter classes represented by this ClassString object.
317:                 * 
318:                 */
319:                private boolean isApplicable(Object method) {
320:                    Class[] methodArgs = getParameterTypes(method);
321:                    if (methodArgs.length != classes.length) {
322:                        return false;
323:                    }
324:                    for (int i = 0; i < classes.length; ++i) {
325:                        if (!isMethodInvocationConvertible(methodArgs[i],
326:                                classes[i])) {
327:                            return false;
328:                        }
329:                    }
330:                    return true;
331:                }
332:
333:                /**
334:                 * Determines whether a type represented by a class object is
335:                 * convertible to another type represented by a class object using a 
336:                 * method invocation conversion, treating object types of primitive 
337:                 * types as if they were primitive types (that is, a Boolean actual 
338:                 * parameter type matches boolean primitive formal type). This behavior
339:                 * is because this method is used to determine applicable methods for 
340:                 * an actual parameter list, and primitive types are represented by 
341:                 * their object duals in reflective method calls.
342:                 * @param formal the formal parameter type to which the actual 
343:                 * parameter type should be convertible
344:                 * @param actual the actual parameter type.
345:                 * @return true if either formal type is assignable from actual type, 
346:                 * or formal is a primitive type and actual is its corresponding object
347:                 * type or an object type of a primitive type that can be converted to
348:                 * the formal type.
349:                 */
350:                private static boolean isMethodInvocationConvertible(
351:                        Class formal, Class actual) {
352:                    // Check for identity or widening reference conversion
353:                    if (formal.isAssignableFrom(actual)) {
354:                        return true;
355:                    }
356:                    // Check for boxing with widening primitive conversion. Note that 
357:                    // actual parameters are never primitives.
358:                    if (formal.isPrimitive()) {
359:                        if (formal == Boolean.TYPE && actual == Boolean.class)
360:                            return true;
361:                        if (formal == Character.TYPE
362:                                && actual == Character.class)
363:                            return true;
364:                        if (formal == Byte.TYPE && actual == Byte.class)
365:                            return true;
366:                        if (formal == Short.TYPE
367:                                && (actual == Short.class || actual == Byte.class))
368:                            return true;
369:                        if (formal == Integer.TYPE
370:                                && (actual == Integer.class
371:                                        || actual == Short.class || actual == Byte.class))
372:                            return true;
373:                        if (formal == Long.TYPE
374:                                && (actual == Long.class
375:                                        || actual == Integer.class
376:                                        || actual == Short.class || actual == Byte.class))
377:                            return true;
378:                        if (formal == Float.TYPE
379:                                && (actual == Float.class
380:                                        || actual == Long.class
381:                                        || actual == Integer.class
382:                                        || actual == Short.class || actual == Byte.class))
383:                            return true;
384:                        if (formal == Double.TYPE
385:                                && (actual == Double.class
386:                                        || actual == Float.class
387:                                        || actual == Long.class
388:                                        || actual == Integer.class
389:                                        || actual == Short.class || actual == Byte.class))
390:                            return true;
391:                    }
392:                    // Special case for BigDecimals as we deem BigDecimal to be
393:                    // convertible to any numeric type - either object or primitive.
394:                    // This can actually cause us trouble as this is a narrowing 
395:                    // conversion, not widening. 
396:                    return isBigDecimalConvertible(formal, actual);
397:                }
398:
399:                private String listArgumentTypes() {
400:                    StringBuffer buf = new StringBuffer(classes.length * 32)
401:                            .append('(');
402:                    for (int i = 0; i < classes.length; ++i) {
403:                        buf.append(classes[i].getName()).append(',');
404:                    }
405:                    buf.setLength(buf.length() - 1);
406:                    return buf.append(')').toString();
407:                }
408:            }
409:
410:            /**
411:             * Determines whether a type represented by a class object is 
412:             * convertible to another type represented by a class object using a 
413:             * method invocation conversion, without matching object and primitive
414:             * types. This method is used to determine the more specific type when
415:             * comparing signatures of methods.
416:             * @return true if either formal type is assignable from actual type, 
417:             * or formal and actual are both primitive types and actual can be
418:             * subject to widening conversion to formal.
419:             */
420:            private static boolean isMoreSpecific(Class specific, Class generic) {
421:                // Check for identity or widening reference conversion
422:                if (generic.isAssignableFrom(specific)) {
423:                    return true;
424:                }
425:                // Check for widening primitive conversion.
426:                if (generic.isPrimitive()) {
427:                    if (generic == Short.TYPE && (specific == Byte.TYPE))
428:                        return true;
429:                    if (generic == Integer.TYPE
430:                            && (specific == Short.TYPE || specific == Byte.TYPE))
431:                        return true;
432:                    if (generic == Long.TYPE
433:                            && (specific == Integer.TYPE
434:                                    || specific == Short.TYPE || specific == Byte.TYPE))
435:                        return true;
436:                    if (generic == Float.TYPE
437:                            && (specific == Long.TYPE
438:                                    || specific == Integer.TYPE
439:                                    || specific == Short.TYPE || specific == Byte.TYPE))
440:                        return true;
441:                    if (generic == Double.TYPE
442:                            && (specific == Float.TYPE || specific == Long.TYPE
443:                                    || specific == Integer.TYPE
444:                                    || specific == Short.TYPE || specific == Byte.TYPE))
445:                        return true;
446:                }
447:                return isBigDecimalConvertible(generic, specific);
448:            }
449:
450:            private static boolean isBigDecimalConvertible(Class formal,
451:                    Class actual) {
452:                // BigDecimal 
453:                if (BIGDECIMAL_CLASS.isAssignableFrom(actual)) {
454:                    if (NUMBER_CLASS.isAssignableFrom(formal)) {
455:                        return true;
456:                    }
457:                    if (formal.isPrimitive() && formal != Boolean.TYPE
458:                            && formal != Character.TYPE) {
459:                        return true;
460:                    }
461:                }
462:                return false;
463:            }
464:
465:            private static Class getMostSpecificCommonType(Class c1, Class c2) {
466:                if (c1 == c2) {
467:                    return c1;
468:                }
469:                if (c2.isPrimitive()) {
470:                    if (c2 == Byte.TYPE)
471:                        c2 = Byte.class;
472:                    else if (c2 == Short.TYPE)
473:                        c2 = Short.class;
474:                    else if (c2 == Character.TYPE)
475:                        c2 = Character.class;
476:                    else if (c2 == Integer.TYPE)
477:                        c2 = Integer.class;
478:                    else if (c2 == Float.TYPE)
479:                        c2 = Float.class;
480:                    else if (c2 == Long.TYPE)
481:                        c2 = Long.class;
482:                    else if (c2 == Double.TYPE)
483:                        c2 = Double.class;
484:                }
485:                Set a1 = getAssignables(c1, c2);
486:                Set a2 = getAssignables(c2, c1);
487:                a1.retainAll(a2);
488:                if (a1.isEmpty()) {
489:                    // Can happen when at least one of the arguments is an interface, as
490:                    // they don't have Object at the root of their hierarchy
491:                    return Object.class;
492:                }
493:                // Gather maximally specific elements. Yes, there can be more than one 
494:                // thank to interfaces. I.e., if you call this method for String.class 
495:                // and Number.class, you'll have Comparable, Serializable, and Object as 
496:                // maximal elements. 
497:                List max = new ArrayList();
498:                outer: for (Iterator iter = a1.iterator(); iter.hasNext();) {
499:                    Class clazz = (Class) iter.next();
500:                    for (Iterator maxiter = max.iterator(); maxiter.hasNext();) {
501:                        Class maxClazz = (Class) maxiter.next();
502:                        if (isMoreSpecific(maxClazz, clazz)) {
503:                            // It can't be maximal, if there's already a more specific
504:                            // maximal than it.
505:                            continue outer;
506:                        }
507:                        if (isMoreSpecific(clazz, maxClazz)) {
508:                            // If it's more specific than a currently maximal element,
509:                            // that currently maximal is no longer a maximal.
510:                            maxiter.remove();
511:                        }
512:                    }
513:                    // If we get here, no current maximal is more specific than the
514:                    // current class, so it is considered maximal as well
515:                    max.add(clazz);
516:                }
517:                if (max.size() > 1) {
518:                    return OBJECT_CLASS;
519:                }
520:                return (Class) max.get(0);
521:            }
522:
523:            private static Set getAssignables(Class c1, Class c2) {
524:                Set s = new HashSet();
525:                collectAssignables(c1, c2, s);
526:                return s;
527:            }
528:
529:            private static void collectAssignables(Class c1, Class c2, Set s) {
530:                if (c1.isAssignableFrom(c2)) {
531:                    s.add(c1);
532:                }
533:                Class sc = c1.getSuperclass();
534:                if (sc != null) {
535:                    collectAssignables(sc, c2, s);
536:                }
537:                Class[] itf = c1.getInterfaces();
538:                for (int i = 0; i < itf.length; ++i) {
539:                    collectAssignables(itf[i], c2, s);
540:                }
541:            }
542:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.