Source Code Cross Referenced for InternalClassTransformationImpl.java in  » Library » Tapestry » org » apache » tapestry » internal » services » 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 » Library » Tapestry » org.apache.tapestry.internal.services 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // Copyright 2006, 2007 The Apache Software Foundation
0002:        //
0003:        // Licensed under the Apache License, Version 2.0 (the "License");
0004:        // you may not use this file except in compliance with the License.
0005:        // You may obtain a copy of the License at
0006:        //
0007:        //     http://www.apache.org/licenses/LICENSE-2.0
0008:        //
0009:        // Unless required by applicable law or agreed to in writing, software
0010:        // distributed under the License is distributed on an "AS IS" BASIS,
0011:        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012:        // See the License for the specific language governing permissions and
0013:        // limitations under the License.
0014:
0015:        package org.apache.tapestry.internal.services;
0016:
0017:        import static java.lang.String.format;
0018:        import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
0019:        import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
0020:        import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
0021:        import static org.apache.tapestry.ioc.internal.util.Defense.notBlank;
0022:        import static org.apache.tapestry.ioc.internal.util.Defense.notNull;
0023:
0024:        import java.lang.annotation.Annotation;
0025:        import java.lang.reflect.Modifier;
0026:        import java.util.Collections;
0027:        import java.util.Formatter;
0028:        import java.util.List;
0029:        import java.util.Map;
0030:        import java.util.Set;
0031:
0032:        import javassist.CannotCompileException;
0033:        import javassist.ClassPool;
0034:        import javassist.CtBehavior;
0035:        import javassist.CtClass;
0036:        import javassist.CtConstructor;
0037:        import javassist.CtField;
0038:        import javassist.CtMember;
0039:        import javassist.CtMethod;
0040:        import javassist.CtNewConstructor;
0041:        import javassist.CtNewMethod;
0042:        import javassist.NotFoundException;
0043:        import javassist.expr.ExprEditor;
0044:        import javassist.expr.FieldAccess;
0045:
0046:        import org.apache.commons.logging.Log;
0047:        import org.apache.tapestry.ComponentResources;
0048:        import org.apache.tapestry.internal.InternalComponentResources;
0049:        import org.apache.tapestry.internal.util.MultiKey;
0050:        import org.apache.tapestry.ioc.internal.util.CollectionFactory;
0051:        import org.apache.tapestry.ioc.internal.util.IdAllocator;
0052:        import org.apache.tapestry.ioc.internal.util.InternalUtils;
0053:        import org.apache.tapestry.model.ComponentModel;
0054:        import org.apache.tapestry.runtime.Component;
0055:        import org.apache.tapestry.services.FieldFilter;
0056:        import org.apache.tapestry.services.MethodFilter;
0057:        import org.apache.tapestry.services.MethodSignature;
0058:        import org.apache.tapestry.services.TransformUtils;
0059:
0060:        /**
0061:         * Implementation of the {@link org.apache.tapestry.internal.services.InternalClassTransformation}
0062:         * interface.
0063:         */
0064:        public final class InternalClassTransformationImpl implements 
0065:                InternalClassTransformation {
0066:            private boolean _frozen;
0067:
0068:            private final CtClass _ctClass;
0069:
0070:            private final Log _log;
0071:
0072:            private final InternalClassTransformation _parentTransformation;
0073:
0074:            private ClassPool _classPool;
0075:
0076:            private final IdAllocator _idAllocator;
0077:
0078:            /** Map, keyed on InjectKey, of field name. */
0079:            private final Map<MultiKey, String> _injectionCache = newMap();
0080:
0081:            /** Map from a field to the annotation objects for that field. */
0082:            private Map<String, List<Annotation>> _fieldAnnotations = newMap();
0083:
0084:            /** Used to identify fields that have been "claimed" by other annotations. */
0085:            private Map<String, Object> _claimedFields = newMap();
0086:
0087:            private Set<String> _addedFieldNames = newSet();
0088:
0089:            private Set<CtBehavior> _addedMethods = newSet();
0090:
0091:            // Cache of class annotations
0092:
0093:            private List<Annotation> _classAnnotations;
0094:
0095:            // Cache of method annotations
0096:
0097:            private Map<CtMethod, List<Annotation>> _methodAnnotations = newMap();
0098:
0099:            private Map<CtMethod, MethodSignature> _methodSignatures = newMap();
0100:
0101:            // Key is field name, value is expression used to replace read access
0102:
0103:            private Map<String, String> _fieldReadTransforms;
0104:
0105:            // Key is field name, value is expression used to replace read access
0106:            private Map<String, String> _fieldWriteTransforms;
0107:
0108:            private Set<String> _removedFieldNames;
0109:
0110:            /** Contains the assembled Javassist code for the class' default constructor. */
0111:            private StringBuilder _constructor = new StringBuilder();
0112:
0113:            private final List<ConstructorArg> _constructorArgs;
0114:
0115:            private final ComponentModel _componentModel;
0116:
0117:            private final String _resourcesFieldName;
0118:
0119:            private final StringBuilder _description = new StringBuilder();
0120:
0121:            private Formatter _formatter = new Formatter(_description);
0122:
0123:            private ClassLoader _loader;
0124:
0125:            /**
0126:             * This is a constructor for the root class, the class that directly contains the ComponentClass
0127:             * annotation.
0128:             */
0129:            public InternalClassTransformationImpl(CtClass ctClass,
0130:                    ClassLoader loader, Log log, ComponentModel componentModel) {
0131:                _ctClass = ctClass;
0132:                _classPool = _ctClass.getClassPool();
0133:                _loader = loader;
0134:                _parentTransformation = null;
0135:                _componentModel = componentModel;
0136:
0137:                _idAllocator = new IdAllocator();
0138:
0139:                _log = log;
0140:
0141:                preloadMemberNames();
0142:
0143:                _constructorArgs = newList();
0144:                _constructor.append("{\n");
0145:
0146:                addImplementedInterface(Component.class);
0147:
0148:                _resourcesFieldName = addInjectedFieldUncached(
0149:                        InternalComponentResources.class, "resources", null);
0150:
0151:                MethodSignature sig = new MethodSignature(Modifier.PUBLIC
0152:                        | Modifier.FINAL, ComponentResources.class.getName(),
0153:                        "getComponentResources", null, null);
0154:
0155:                addMethod(sig, "return " + _resourcesFieldName + ";");
0156:            }
0157:
0158:            public InternalClassTransformationImpl(CtClass ctClass,
0159:                    InternalClassTransformation parentTransformation,
0160:                    ClassLoader loader, Log log, ComponentModel componentModel) {
0161:                _ctClass = ctClass;
0162:                _classPool = _ctClass.getClassPool();
0163:                _loader = loader;
0164:                _log = log;
0165:                _parentTransformation = parentTransformation;
0166:                _componentModel = componentModel;
0167:
0168:                _resourcesFieldName = parentTransformation
0169:                        .getResourcesFieldName();
0170:
0171:                _idAllocator = parentTransformation.getIdAllocator();
0172:
0173:                preloadMemberNames();
0174:
0175:                verifyFields();
0176:
0177:                _constructorArgs = parentTransformation.getConstructorArgs();
0178:
0179:                int count = _constructorArgs.size();
0180:
0181:                // Build the call to the super-constructor.
0182:
0183:                _constructor.append("{ super(");
0184:
0185:                for (int i = 1; i <= count; i++) {
0186:                    if (i > 1)
0187:                        _constructor.append(", ");
0188:
0189:                    // $0 is implicitly self, so the 0-index ConstructorArg will be Javassisst
0190:                    // pseudeo-variable $1, and so forth.
0191:
0192:                    _constructor.append("$" + i);
0193:                }
0194:
0195:                _constructor.append(");\n");
0196:
0197:                // The "}" will be added later, inside
0198:            }
0199:
0200:            private void freeze() {
0201:                _frozen = true;
0202:
0203:                // Free up stuff we don't need after freezing.
0204:                // Everything else should be final.
0205:
0206:                _fieldAnnotations = null;
0207:                _claimedFields = null;
0208:                _addedFieldNames = null;
0209:                _addedMethods = null;
0210:                _classAnnotations = null;
0211:                _methodAnnotations = null;
0212:                _methodSignatures = null;
0213:                _fieldReadTransforms = null;
0214:                _fieldWriteTransforms = null;
0215:                _removedFieldNames = null;
0216:                _constructor = null;
0217:                _formatter = null;
0218:                _loader = null;
0219:                // _ctClass = null; -- needed by toString()
0220:                _classPool = null;
0221:            }
0222:
0223:            public String getResourcesFieldName() {
0224:                return _resourcesFieldName;
0225:            }
0226:
0227:            /** Loads the names of all declared fields and methods into the idAllocator. */
0228:
0229:            private void preloadMemberNames() {
0230:                addMemberNames(_ctClass.getDeclaredFields());
0231:                addMemberNames(_ctClass.getDeclaredMethods());
0232:            }
0233:
0234:            public void verifyFields() {
0235:                List<String> names = newList();
0236:
0237:                for (CtField field : _ctClass.getDeclaredFields()) {
0238:                    String name = field.getName();
0239:
0240:                    if (_addedFieldNames.contains(name))
0241:                        continue;
0242:
0243:                    int modifiers = field.getModifiers();
0244:
0245:                    // Fields must be either static or private.
0246:
0247:                    if (Modifier.isStatic(modifiers)
0248:                            || Modifier.isPrivate(modifiers))
0249:                        continue;
0250:
0251:                    names.add(name);
0252:                }
0253:
0254:                if (!names.isEmpty()) {
0255:                    Collections.sort(names);
0256:
0257:                    _log.error(ServicesMessages.nonPrivateFields(
0258:                            getClassName(), names));
0259:                }
0260:            }
0261:
0262:            private void addMemberNames(CtMember[] members) {
0263:                for (CtMember member : members) {
0264:                    _idAllocator.allocateId(member.getName());
0265:                }
0266:            }
0267:
0268:            public <T extends Annotation> T getFieldAnnotation(
0269:                    String fieldName, Class<T> annotationClass) {
0270:                failIfFrozen();
0271:
0272:                List<Annotation> annotations = findFieldAnnotations(fieldName);
0273:
0274:                return findAnnotationInList(annotationClass, annotations);
0275:            }
0276:
0277:            public <T extends Annotation> T getMethodAnnotation(
0278:                    MethodSignature signature, Class<T> annotationClass) {
0279:                failIfFrozen();
0280:
0281:                CtMethod method = findMethod(signature);
0282:
0283:                if (method == null)
0284:                    throw new IllegalArgumentException(ServicesMessages
0285:                            .noDeclaredMethod(_ctClass, signature));
0286:
0287:                List<Annotation> annotations = findMethodAnnotations(method);
0288:
0289:                return findAnnotationInList(annotationClass, annotations);
0290:            }
0291:
0292:            /**
0293:             * Searches an array of objects (that are really annotations instances) to find one that is of
0294:             * the correct type, which is returned.
0295:             * 
0296:             * @param <T>
0297:             * @param annotationClass
0298:             *            the annotation to search for
0299:             * @param annotations
0300:             *            the available annotations
0301:             * @return the matching annotation instance, or null if not found
0302:             */
0303:            private <T extends Annotation> T findAnnotationInList(
0304:                    Class<T> annotationClass, List<Annotation> annotations) {
0305:                for (Object annotation : annotations) {
0306:                    if (annotationClass.isInstance(annotation))
0307:                        return annotationClass.cast(annotation);
0308:                }
0309:
0310:                return null;
0311:            }
0312:
0313:            public <T extends Annotation> T getAnnotation(
0314:                    Class<T> annotationClass) {
0315:                return findAnnotationInList(annotationClass,
0316:                        getClassAnnotations());
0317:            }
0318:
0319:            private List<Annotation> findFieldAnnotations(String fieldName) {
0320:                List<Annotation> annotations = _fieldAnnotations.get(fieldName);
0321:
0322:                if (annotations == null) {
0323:                    annotations = findAnnotationsForField(fieldName);
0324:                    _fieldAnnotations.put(fieldName, annotations);
0325:                }
0326:
0327:                return annotations;
0328:            }
0329:
0330:            private List<Annotation> findMethodAnnotations(CtMethod method) {
0331:                List<Annotation> annotations = _methodAnnotations.get(method);
0332:
0333:                if (annotations == null) {
0334:                    annotations = extractAnnotations(method);
0335:
0336:                    _methodAnnotations.put(method, annotations);
0337:                }
0338:
0339:                return annotations;
0340:            }
0341:
0342:            private List<Annotation> findAnnotationsForField(String fieldName) {
0343:                CtField field = findDeclaredCtField(fieldName);
0344:
0345:                return extractAnnotations(field);
0346:            }
0347:
0348:            private List<Annotation> extractAnnotations(CtMember member) {
0349:                try {
0350:                    List<Annotation> result = newList();
0351:
0352:                    addAnnotationsToList(result, member.getAnnotations());
0353:
0354:                    return result;
0355:                } catch (ClassNotFoundException ex) {
0356:                    throw new RuntimeException(ex);
0357:                }
0358:            }
0359:
0360:            private void addAnnotationsToList(List<Annotation> list,
0361:                    Object[] annotations) {
0362:                for (Object o : annotations) {
0363:                    Annotation a = (Annotation) o;
0364:                    list.add(a);
0365:                }
0366:            }
0367:
0368:            private CtField findDeclaredCtField(String fieldName) {
0369:                try {
0370:                    return _ctClass.getDeclaredField(fieldName);
0371:                } catch (NotFoundException ex) {
0372:                    throw new RuntimeException(ServicesMessages
0373:                            .missingDeclaredField(_ctClass, fieldName), ex);
0374:                }
0375:            }
0376:
0377:            public String newMemberName(String suggested) {
0378:                failIfFrozen();
0379:
0380:                String memberName = InternalUtils.createMemberName(notBlank(
0381:                        suggested, "suggested"));
0382:
0383:                return _idAllocator.allocateId(memberName);
0384:            }
0385:
0386:            public String newMemberName(String prefix, String baseName) {
0387:                return newMemberName(prefix + "_"
0388:                        + InternalUtils.stripMemberPrefix(baseName));
0389:            }
0390:
0391:            public void addImplementedInterface(Class interfaceClass) {
0392:                failIfFrozen();
0393:
0394:                String interfaceName = interfaceClass.getName();
0395:
0396:                try {
0397:                    CtClass ctInterface = _classPool.get(interfaceName);
0398:
0399:                    if (classImplementsInterface(ctInterface))
0400:                        return;
0401:
0402:                    implementDefaultMethodsForInterface(ctInterface);
0403:
0404:                    _ctClass.addInterface(ctInterface);
0405:
0406:                } catch (NotFoundException ex) {
0407:                    throw new RuntimeException(ex);
0408:                }
0409:
0410:            }
0411:
0412:            /**
0413:             * Adds default implementations for the methods defined by the interface (and all of its
0414:             * super-interfaces). The implementations return null (or 0, or false, as appropriate to to the
0415:             * method type). There are a number of degenerate cases that are not covered properly: these are
0416:             * related to base interfaces that may be implemented by base classes.
0417:             * 
0418:             * @param ctInterface
0419:             * @throws NotFoundException
0420:             */
0421:            private void implementDefaultMethodsForInterface(CtClass ctInterface)
0422:                    throws NotFoundException {
0423:                // java.lang.Object is the parent interface of interfaces
0424:
0425:                if (ctInterface.getName().equals(Object.class.getName()))
0426:                    return;
0427:
0428:                for (CtMethod method : ctInterface.getDeclaredMethods()) {
0429:                    addDefaultImplementation(method);
0430:                }
0431:
0432:                for (CtClass parent : ctInterface.getInterfaces()) {
0433:                    implementDefaultMethodsForInterface(parent);
0434:                }
0435:            }
0436:
0437:            private void addDefaultImplementation(CtMethod method)
0438:                    throws NotFoundException {
0439:                // Javassist has an oddity for interfaces: methods "inherited" from java.lang.Object show
0440:                // up as methods of the interface. We skip those and only consider the methods
0441:                // that are abstract.
0442:
0443:                if (!Modifier.isAbstract(method.getModifiers()))
0444:                    return;
0445:
0446:                try {
0447:                    CtMethod newMethod = CtNewMethod.copy(method, _ctClass,
0448:                            null);
0449:
0450:                    // Methods from interfaces are always public. We definitely
0451:                    // need to change the modifiers of the method so that
0452:                    // it is not abstract.
0453:
0454:                    newMethod.setModifiers(Modifier.PUBLIC);
0455:
0456:                    // Javassist will provide a minimal implementation for us (return null, false, 0,
0457:                    // whatever).
0458:
0459:                    newMethod.setBody(null);
0460:
0461:                    _ctClass.addMethod(newMethod);
0462:
0463:                    MethodSignature sig = getMethodSignature(newMethod);
0464:
0465:                    addMethodToDescription("add default", sig, "<default>");
0466:                } catch (CannotCompileException ex) {
0467:                    throw new RuntimeException(ServicesMessages
0468:                            .errorAddingMethod(_ctClass, method.getName(), ex),
0469:                            ex);
0470:                }
0471:
0472:            }
0473:
0474:            /**
0475:             * Check to see if the target class (or any of its super classes) implements the provided
0476:             * interface. This is geared for simple interfaces (that don't extend other interfaces), thus if
0477:             * the class (or a base class) implement interface Y that extends interface X, we may not return
0478:             * true for interface X.
0479:             */
0480:
0481:            private boolean classImplementsInterface(CtClass ctInterface)
0482:                    throws NotFoundException {
0483:
0484:                for (CtClass current = _ctClass; current != null; current = current
0485:                        .getSuperclass()) {
0486:                    for (CtClass anInterface : current.getInterfaces()) {
0487:                        if (anInterface == ctInterface)
0488:                            return true;
0489:                    }
0490:                }
0491:
0492:                return false;
0493:            }
0494:
0495:            public void claimField(String fieldName, Object tag) {
0496:                notBlank(fieldName, "fieldName");
0497:                notNull(tag, "tag");
0498:
0499:                failIfFrozen();
0500:
0501:                Object existing = _claimedFields.get(fieldName);
0502:
0503:                if (existing != null) {
0504:                    String message = ServicesMessages.fieldAlreadyClaimed(
0505:                            fieldName, _ctClass, existing, tag);
0506:
0507:                    throw new RuntimeException(message);
0508:                }
0509:
0510:                // TODO: Ensure that fieldName is a known field?
0511:
0512:                _claimedFields.put(fieldName, tag);
0513:            }
0514:
0515:            public void addMethod(MethodSignature signature, String methodBody) {
0516:                failIfFrozen();
0517:
0518:                CtClass returnType = findCtClass(signature.getReturnType());
0519:                CtClass[] parameters = buildCtClassList(signature
0520:                        .getParameterTypes());
0521:                CtClass[] exceptions = buildCtClassList(signature
0522:                        .getExceptionTypes());
0523:
0524:                String action = "add";
0525:
0526:                try {
0527:                    CtMethod existing = _ctClass.getDeclaredMethod(signature
0528:                            .getMethodName(), parameters);
0529:
0530:                    if (existing != null) {
0531:                        action = "replace";
0532:
0533:                        _ctClass.removeMethod(existing);
0534:                    }
0535:                } catch (NotFoundException ex) {
0536:                    // That's ok. Kind of sloppy to rely on a thrown exception; wish getDeclaredMethod()
0537:                    // would return null for
0538:                    // that case. Alternately, we could maintain a set of the method signatures of declared
0539:                    // or added methods.
0540:                }
0541:
0542:                try {
0543:
0544:                    CtMethod method = new CtMethod(returnType, signature
0545:                            .getMethodName(), parameters, _ctClass);
0546:
0547:                    // TODO: Check for duplicate method add
0548:
0549:                    method.setModifiers(signature.getModifiers());
0550:
0551:                    method.setBody(methodBody);
0552:                    method.setExceptionTypes(exceptions);
0553:
0554:                    _ctClass.addMethod(method);
0555:
0556:                    _addedMethods.add(method);
0557:                } catch (CannotCompileException ex) {
0558:                    throw new MethodCompileException(ServicesMessages
0559:                            .methodCompileError(signature, methodBody, ex),
0560:                            methodBody, ex);
0561:                } catch (NotFoundException ex) {
0562:                    throw new RuntimeException(ex);
0563:                }
0564:
0565:                addMethodToDescription(action, signature, methodBody);
0566:            }
0567:
0568:            private CtClass[] buildCtClassList(String[] typeNames) {
0569:                CtClass[] result = new CtClass[typeNames.length];
0570:
0571:                for (int i = 0; i < typeNames.length; i++)
0572:                    result[i] = findCtClass(typeNames[i]);
0573:
0574:                return result;
0575:            }
0576:
0577:            private CtClass findCtClass(String type) {
0578:                try {
0579:                    return _classPool.get(type);
0580:                } catch (NotFoundException ex) {
0581:                    throw new RuntimeException(ex);
0582:                }
0583:            }
0584:
0585:            public void extendMethod(MethodSignature methodSignature,
0586:                    String methodBody) {
0587:                failIfFrozen();
0588:
0589:                CtMethod method = findMethod(methodSignature);
0590:
0591:                try {
0592:                    method.insertAfter(methodBody);
0593:                } catch (CannotCompileException ex) {
0594:                    throw new MethodCompileException(
0595:                            ServicesMessages.methodCompileError(
0596:                                    methodSignature, methodBody, ex),
0597:                            methodBody, ex);
0598:                }
0599:
0600:                addMethodToDescription("extend", methodSignature, methodBody);
0601:
0602:                _addedMethods.add(method);
0603:            }
0604:
0605:            private void addMethodToDescription(String operation,
0606:                    MethodSignature methodSignature, String methodBody) {
0607:                _formatter.format("%s method: %s %s %s(", operation, Modifier
0608:                        .toString(methodSignature.getModifiers()),
0609:                        methodSignature.getReturnType(), methodSignature
0610:                                .getMethodName());
0611:
0612:                String[] parameterTypes = methodSignature.getParameterTypes();
0613:                for (int i = 0; i < parameterTypes.length; i++) {
0614:                    if (i > 0)
0615:                        _description.append(", ");
0616:
0617:                    _formatter.format("%s $%d", parameterTypes[i], i + 1);
0618:                }
0619:
0620:                _description.append(")");
0621:
0622:                String[] exceptionTypes = methodSignature.getExceptionTypes();
0623:                for (int i = 0; i < exceptionTypes.length; i++) {
0624:                    if (i == 0)
0625:                        _description.append("\n  throws ");
0626:                    else
0627:                        _description.append(", ");
0628:
0629:                    _description.append(exceptionTypes[i]);
0630:                }
0631:
0632:                _formatter.format("\n%s\n\n", methodBody);
0633:            }
0634:
0635:            private CtMethod findMethod(MethodSignature methodSignature) {
0636:                CtMethod method = findDeclaredMethod(methodSignature);
0637:
0638:                if (method != null)
0639:                    return method;
0640:
0641:                CtMethod result = addOverrideOfSuperclassMethod(methodSignature);
0642:
0643:                if (result != null)
0644:                    return result;
0645:
0646:                throw new IllegalArgumentException(ServicesMessages
0647:                        .noDeclaredMethod(_ctClass, methodSignature));
0648:            }
0649:
0650:            private CtMethod findDeclaredMethod(MethodSignature methodSignature) {
0651:                for (CtMethod method : _ctClass.getDeclaredMethods()) {
0652:                    if (match(method, methodSignature))
0653:                        return method;
0654:                }
0655:
0656:                return null;
0657:            }
0658:
0659:            private CtMethod addOverrideOfSuperclassMethod(
0660:                    MethodSignature methodSignature) {
0661:                try {
0662:                    for (CtClass current = _ctClass; current != null; current = current
0663:                            .getSuperclass()) {
0664:                        for (CtMethod method : current.getDeclaredMethods()) {
0665:                            if (match(method, methodSignature)) {
0666:                                // TODO: If the moethod is not overridable (i.e. private, or final)?
0667:                                // Perhaps we should limit it to just public methods.
0668:
0669:                                CtMethod newMethod = CtNewMethod.delegator(
0670:                                        method, _ctClass);
0671:                                _ctClass.addMethod(newMethod);
0672:
0673:                                return newMethod;
0674:                            }
0675:                        }
0676:                    }
0677:                } catch (NotFoundException ex) {
0678:                    throw new RuntimeException(ex);
0679:                } catch (CannotCompileException ex) {
0680:                    throw new RuntimeException(ex);
0681:                }
0682:
0683:                // Not found in a super-class.
0684:
0685:                return null;
0686:            }
0687:
0688:            private boolean match(CtMethod method, MethodSignature sig) {
0689:                if (!sig.getMethodName().equals(method.getName()))
0690:                    return false;
0691:
0692:                CtClass[] paramTypes;
0693:
0694:                try {
0695:                    paramTypes = method.getParameterTypes();
0696:                } catch (NotFoundException ex) {
0697:                    throw new RuntimeException(ex);
0698:                }
0699:
0700:                String[] sigTypes = sig.getParameterTypes();
0701:
0702:                int count = sigTypes.length;
0703:
0704:                if (paramTypes.length != count)
0705:                    return false;
0706:
0707:                for (int i = 0; i < count; i++) {
0708:                    String paramType = paramTypes[i].getName();
0709:
0710:                    if (!paramType.equals(sigTypes[i]))
0711:                        return false;
0712:                }
0713:
0714:                // Ignore exceptions thrown and modifiers.
0715:                // TODO: Validate a match on return type?
0716:
0717:                return true;
0718:            }
0719:
0720:            public List<String> findFieldsWithAnnotation(
0721:                    final Class<? extends Annotation> annotationClass) {
0722:                FieldFilter filter = new FieldFilter() {
0723:                    public boolean accept(String fieldName, String fieldType) {
0724:                        return getFieldAnnotation(fieldName, annotationClass) != null;
0725:                    }
0726:                };
0727:
0728:                return findFields(filter);
0729:            }
0730:
0731:            public List<String> findFields(FieldFilter filter) {
0732:                failIfFrozen();
0733:
0734:                List<String> result = newList();
0735:
0736:                try {
0737:                    for (CtField field : _ctClass.getDeclaredFields()) {
0738:                        if (!isInstanceField(field))
0739:                            continue;
0740:
0741:                        String fieldName = field.getName();
0742:
0743:                        if (_claimedFields.containsKey(fieldName))
0744:                            continue;
0745:
0746:                        if (filter.accept(fieldName, field.getType().getName()))
0747:                            result.add(fieldName);
0748:
0749:                    }
0750:                } catch (NotFoundException ex) {
0751:                    throw new RuntimeException(ex);
0752:                }
0753:
0754:                Collections.sort(result);
0755:
0756:                return result;
0757:            }
0758:
0759:            public List<String> findFieldsOfType(final String type) {
0760:                FieldFilter filter = new FieldFilter() {
0761:                    public boolean accept(String fieldName, String fieldType) {
0762:                        return type.equals(fieldType);
0763:                    }
0764:                };
0765:
0766:                return findFields(filter);
0767:            }
0768:
0769:            public List<MethodSignature> findMethodsWithAnnotation(
0770:                    Class<? extends Annotation> annotationClass) {
0771:                failIfFrozen();
0772:
0773:                List<MethodSignature> result = newList();
0774:
0775:                for (CtMethod method : _ctClass.getDeclaredMethods()) {
0776:                    List<Annotation> annotations = findMethodAnnotations(method);
0777:
0778:                    if (findAnnotationInList(annotationClass, annotations) != null) {
0779:                        MethodSignature sig = getMethodSignature(method);
0780:                        result.add(sig);
0781:                    }
0782:                }
0783:
0784:                Collections.sort(result);
0785:
0786:                return result;
0787:            }
0788:
0789:            public List<MethodSignature> findMethods(MethodFilter filter) {
0790:                notNull(filter, "filter");
0791:
0792:                List<MethodSignature> result = newList();
0793:
0794:                for (CtMethod method : _ctClass.getDeclaredMethods()) {
0795:                    MethodSignature sig = getMethodSignature(method);
0796:
0797:                    if (filter.accept(sig))
0798:                        result.add(sig);
0799:                }
0800:
0801:                Collections.sort(result);
0802:
0803:                return result;
0804:            }
0805:
0806:            private MethodSignature getMethodSignature(CtMethod method) {
0807:                MethodSignature result = _methodSignatures.get(method);
0808:                if (result == null) {
0809:                    try {
0810:                        String type = method.getReturnType().getName();
0811:                        String[] parameters = toTypeNames(method
0812:                                .getParameterTypes());
0813:                        String[] exceptions = toTypeNames(method
0814:                                .getExceptionTypes());
0815:
0816:                        result = new MethodSignature(method.getModifiers(),
0817:                                type, method.getName(), parameters, exceptions);
0818:
0819:                        _methodSignatures.put(method, result);
0820:                    } catch (NotFoundException ex) {
0821:                        throw new RuntimeException(ex);
0822:                    }
0823:                }
0824:
0825:                return result;
0826:            }
0827:
0828:            private String[] toTypeNames(CtClass[] types) {
0829:                String[] result = new String[types.length];
0830:
0831:                for (int i = 0; i < types.length; i++)
0832:                    result[i] = types[i].getName();
0833:
0834:                return result;
0835:            }
0836:
0837:            public List<String> findUnclaimedFields() {
0838:                failIfFrozen();
0839:
0840:                List<String> names = newList();
0841:
0842:                Set<String> skipped = newSet();
0843:
0844:                skipped.addAll(_claimedFields.keySet());
0845:                skipped.addAll(_addedFieldNames);
0846:
0847:                if (_removedFieldNames != null)
0848:                    skipped.addAll(_removedFieldNames);
0849:
0850:                for (CtField field : _ctClass.getDeclaredFields()) {
0851:                    if (!isInstanceField(field))
0852:                        continue;
0853:
0854:                    String name = field.getName();
0855:
0856:                    if (skipped.contains(name))
0857:                        continue;
0858:
0859:                    // May need to add a filter to edit out explicitly added fields.
0860:
0861:                    names.add(name);
0862:                }
0863:
0864:                Collections.sort(names);
0865:
0866:                return names;
0867:            }
0868:
0869:            private boolean isInstanceField(CtField field) {
0870:                int modifiers = field.getModifiers();
0871:
0872:                return Modifier.isPrivate(modifiers)
0873:                        && !Modifier.isStatic(modifiers);
0874:            }
0875:
0876:            public String getFieldType(String fieldName) {
0877:                failIfFrozen();
0878:
0879:                CtClass type = getFieldCtType(fieldName);
0880:
0881:                return type.getName();
0882:            }
0883:
0884:            public boolean isField(String fieldName) {
0885:                failIfFrozen();
0886:
0887:                try {
0888:                    CtField field = _ctClass.getDeclaredField(fieldName);
0889:
0890:                    return isInstanceField(field);
0891:                } catch (NotFoundException ex) {
0892:                    return false;
0893:                }
0894:            }
0895:
0896:            public int getFieldModifiers(String fieldName) {
0897:                failIfFrozen();
0898:
0899:                try {
0900:                    return _ctClass.getDeclaredField(fieldName).getModifiers();
0901:                } catch (NotFoundException ex) {
0902:                    throw new RuntimeException(ex);
0903:                }
0904:            }
0905:
0906:            private CtClass getFieldCtType(String fieldName) {
0907:                try {
0908:                    CtField field = _ctClass.getDeclaredField(fieldName);
0909:
0910:                    return field.getType();
0911:                } catch (NotFoundException ex) {
0912:                    throw new RuntimeException(ex);
0913:                }
0914:            }
0915:
0916:            public String addField(int modifiers, String type,
0917:                    String suggestedName) {
0918:                failIfFrozen();
0919:
0920:                String fieldName = newMemberName(suggestedName);
0921:
0922:                try {
0923:                    CtClass ctType = convertNameToCtType(type);
0924:
0925:                    CtField field = new CtField(ctType, fieldName, _ctClass);
0926:                    field.setModifiers(modifiers);
0927:
0928:                    _ctClass.addField(field);
0929:                } catch (NotFoundException ex) {
0930:                    throw new RuntimeException(ex);
0931:                } catch (CannotCompileException ex) {
0932:                    throw new RuntimeException(ex);
0933:                }
0934:
0935:                _formatter.format("add field: %s %s %s;\n\n", Modifier
0936:                        .toString(modifiers), type, fieldName);
0937:
0938:                _addedFieldNames.add(fieldName);
0939:
0940:                return fieldName;
0941:            }
0942:
0943:            public String addInjectedField(Class type, String suggestedName,
0944:                    Object value) {
0945:                notNull(type, "type");
0946:
0947:                failIfFrozen();
0948:
0949:                MultiKey key = new MultiKey(type, value);
0950:
0951:                String fieldName = searchForPreviousInjection(key);
0952:
0953:                if (fieldName != null)
0954:                    return fieldName;
0955:
0956:                // TODO: Probably doesn't handle arrays and primitives.
0957:
0958:                fieldName = addInjectedFieldUncached(type, suggestedName, value);
0959:
0960:                // Remember the injection in-case this class, or a subclass, injects the value again.
0961:
0962:                _injectionCache.put(key, fieldName);
0963:
0964:                return fieldName;
0965:            }
0966:
0967:            /**
0968:             * This is split out from {@link #addInjectedField(Class, String, Object)} to handle a special
0969:             * case for the InternalComponentResources, which is null when "injected" (during the class
0970:             * transformation) and is only determined when a component is actually instantiated.
0971:             */
0972:            private String addInjectedFieldUncached(Class type,
0973:                    String suggestedName, Object value) {
0974:                CtClass ctType;
0975:
0976:                try {
0977:                    ctType = _classPool.get(type.getName());
0978:                } catch (NotFoundException ex) {
0979:                    throw new RuntimeException(ex);
0980:                }
0981:
0982:                String fieldName = addField(
0983:                        Modifier.PROTECTED | Modifier.FINAL, type.getName(),
0984:                        suggestedName);
0985:
0986:                addInjectToConstructor(fieldName, ctType, value);
0987:
0988:                return fieldName;
0989:            }
0990:
0991:            public String searchForPreviousInjection(MultiKey key) {
0992:                String result = _injectionCache.get(key);
0993:
0994:                if (result != null)
0995:                    return result;
0996:
0997:                if (_parentTransformation != null)
0998:                    return _parentTransformation
0999:                            .searchForPreviousInjection(key);
1000:
1001:                return null;
1002:            }
1003:
1004:            /**
1005:             * Adds a parameter to the constructor for the class; the parameter is used to initialize the
1006:             * value for a field.
1007:             * 
1008:             * @param fieldName
1009:             *            name of field to inject
1010:             * @param fieldType
1011:             *            Javassist type of the field (and corresponding parameter)
1012:             * @param value
1013:             *            the value to be injected (which will in unusual cases be null)
1014:             */
1015:            private void addInjectToConstructor(String fieldName,
1016:                    CtClass fieldType, Object value) {
1017:                _constructorArgs.add(new ConstructorArg(fieldType, value));
1018:
1019:                extendConstructor(format("  %s = $%d;", fieldName,
1020:                        _constructorArgs.size()));
1021:            }
1022:
1023:            public void injectField(String fieldName, Object value) {
1024:                notNull(fieldName, "fieldName");
1025:
1026:                failIfFrozen();
1027:
1028:                CtClass type = getFieldCtType(fieldName);
1029:
1030:                addInjectToConstructor(fieldName, type, value);
1031:
1032:                makeReadOnly(fieldName);
1033:            }
1034:
1035:            private CtClass convertNameToCtType(String type)
1036:                    throws NotFoundException {
1037:                return _classPool.get(type);
1038:            }
1039:
1040:            public void finish() {
1041:                failIfFrozen();
1042:
1043:                performFieldTransformations();
1044:
1045:                addConstructor();
1046:
1047:                verifyFields();
1048:
1049:                freeze();
1050:            }
1051:
1052:            private void addConstructor() {
1053:                String initializer = _idAllocator.allocateId("initializer");
1054:
1055:                try {
1056:                    CtConstructor defaultConstructor = _ctClass
1057:                            .getConstructor("()V");
1058:
1059:                    CtMethod initializerMethod = defaultConstructor.toMethod(
1060:                            initializer, _ctClass);
1061:
1062:                    _ctClass.addMethod(initializerMethod);
1063:                } catch (Exception ex) {
1064:                    throw new RuntimeException(ex);
1065:                }
1066:
1067:                _formatter.format("convert default constructor: %s();\n\n",
1068:                        initializer);
1069:
1070:                int count = _constructorArgs.size();
1071:
1072:                CtClass[] types = new CtClass[count];
1073:
1074:                for (int i = 0; i < count; i++) {
1075:                    ConstructorArg arg = _constructorArgs.get(i);
1076:
1077:                    types[i] = arg.getType();
1078:                }
1079:
1080:                // Add a call to the initializer; the method converted fromt the classes default
1081:                // constructor.
1082:
1083:                _constructor.append("  ");
1084:                _constructor.append(initializer);
1085:
1086:                // This finally matches the "{" added inside the constructor
1087:
1088:                _constructor.append("();\n\n}");
1089:
1090:                String constructorBody = _constructor.toString();
1091:
1092:                try {
1093:                    CtConstructor cons = CtNewConstructor.make(types, null,
1094:                            constructorBody, _ctClass);
1095:                    _ctClass.addConstructor(cons);
1096:                } catch (CannotCompileException ex) {
1097:                    throw new RuntimeException(ex);
1098:                }
1099:
1100:                _formatter.format("add constructor: %s(", _ctClass.getName());
1101:
1102:                for (int i = 0; i < count; i++) {
1103:                    if (i > 0)
1104:                        _description.append(", ");
1105:
1106:                    _formatter.format("%s $%d", types[i].getName(), i + 1);
1107:                }
1108:
1109:                _formatter.format(")\n%s\n\n", constructorBody);
1110:            }
1111:
1112:            public Instantiator createInstantiator(Class componentClass) {
1113:                String className = _ctClass.getName();
1114:
1115:                if (!className.equals(componentClass.getName()))
1116:                    throw new IllegalArgumentException(ServicesMessages
1117:                            .incorrectClassForInstantiator(className,
1118:                                    componentClass));
1119:
1120:                Object[] parameters = new Object[_constructorArgs.size()];
1121:
1122:                // Skip the first constructor argument, it's always a placeholder
1123:                // for the InternalComponentResources instance that's provided
1124:                // later.
1125:
1126:                for (int i = 1; i < _constructorArgs.size(); i++) {
1127:                    parameters[i] = _constructorArgs.get(i).getValue();
1128:                }
1129:
1130:                return new ReflectiveInstantiator(_componentModel,
1131:                        componentClass, parameters);
1132:            }
1133:
1134:            private void failIfFrozen() {
1135:                if (_frozen)
1136:                    throw new IllegalStateException(
1137:                            "The ClassTransformation instance (for "
1138:                                    + _ctClass.getName()
1139:                                    + ") has completed all transformations and may not be further modified.");
1140:            }
1141:
1142:            private void failIfNotFrozen() {
1143:                if (!_frozen)
1144:                    throw new IllegalStateException(
1145:                            "The ClassTransformation instance (for "
1146:                                    + _ctClass.getName()
1147:                                    + ") has not yet completed all transformations.");
1148:            }
1149:
1150:            public IdAllocator getIdAllocator() {
1151:                failIfNotFrozen();
1152:
1153:                return _idAllocator;
1154:            }
1155:
1156:            public List<ConstructorArg> getConstructorArgs() {
1157:                failIfNotFrozen();
1158:
1159:                return CollectionFactory.newList(_constructorArgs);
1160:            }
1161:
1162:            public List<Annotation> getClassAnnotations() {
1163:                failIfFrozen();
1164:
1165:                if (_classAnnotations == null)
1166:                    assembleClassAnnotations();
1167:
1168:                return _classAnnotations;
1169:            }
1170:
1171:            private void assembleClassAnnotations() {
1172:                _classAnnotations = newList();
1173:
1174:                try {
1175:                    for (CtClass current = _ctClass; current != null; current = current
1176:                            .getSuperclass()) {
1177:                        addAnnotationsToList(_classAnnotations, current
1178:                                .getAnnotations());
1179:                    }
1180:                } catch (NotFoundException ex) {
1181:                    throw new RuntimeException(ex);
1182:                } catch (ClassNotFoundException ex) {
1183:                    throw new RuntimeException(ex);
1184:                }
1185:            }
1186:
1187:            @Override
1188:            public String toString() {
1189:                StringBuilder builder = new StringBuilder(
1190:                        "InternalClassTransformation[\n");
1191:
1192:                try {
1193:                    Formatter formatter = new Formatter(builder);
1194:
1195:                    formatter.format("%s %s extends %s", Modifier
1196:                            .toString(_ctClass.getModifiers()), _ctClass
1197:                            .getName(), _ctClass.getSuperclass().getName());
1198:
1199:                    CtClass[] interfaces = _ctClass.getInterfaces();
1200:
1201:                    for (int i = 0; i < interfaces.length; i++) {
1202:                        if (i == 0)
1203:                            builder.append("\n  implements ");
1204:                        else
1205:                            builder.append(", ");
1206:
1207:                        builder.append(interfaces[i].getName());
1208:                    }
1209:
1210:                    formatter.format("\n\n%s", _description.toString());
1211:                } catch (NotFoundException ex) {
1212:                    builder.append(ex);
1213:                }
1214:
1215:                builder.append("]");
1216:
1217:                return builder.toString();
1218:            }
1219:
1220:            public void makeReadOnly(String fieldName) {
1221:                String methodName = newMemberName("write", fieldName);
1222:
1223:                String fieldType = getFieldType(fieldName);
1224:
1225:                MethodSignature sig = new MethodSignature(Modifier.PRIVATE,
1226:                        "void", methodName, new String[] { fieldType }, null);
1227:
1228:                String message = ServicesMessages.readOnlyField(_ctClass
1229:                        .getName(), fieldName);
1230:
1231:                String body = format(
1232:                        "throw new java.lang.RuntimeException(\"%s\");",
1233:                        message);
1234:
1235:                addMethod(sig, body);
1236:
1237:                replaceWriteAccess(fieldName, methodName);
1238:            }
1239:
1240:            public void removeField(String fieldName) {
1241:                _formatter.format("remove field %s;\n\n", fieldName);
1242:
1243:                // TODO: We could check that there's an existing field read and field write transform ...
1244:
1245:                if (_removedFieldNames == null)
1246:                    _removedFieldNames = newSet();
1247:
1248:                _removedFieldNames.add(fieldName);
1249:
1250:            }
1251:
1252:            public void replaceReadAccess(String fieldName, String methodName) {
1253:                // Explicitly reference $0 (aka "this") because of TAPESTRY-1511.
1254:                // $0 is valid even inside a static method.
1255:
1256:                String body = String.format("$_ = $0.%s();", methodName);
1257:
1258:                if (_fieldReadTransforms == null)
1259:                    _fieldReadTransforms = newMap();
1260:
1261:                // TODO: Collisions?
1262:
1263:                _fieldReadTransforms.put(fieldName, body);
1264:
1265:                _formatter.format("replace read %s: %s();\n\n", fieldName,
1266:                        methodName);
1267:            }
1268:
1269:            public void replaceWriteAccess(String fieldName, String methodName) {
1270:                // Explicitly reference $0 (aka "this") because of TAPESTRY-1511.
1271:                // $0 is valid even inside a static method.
1272:
1273:                String body = String.format("$0.%s($1);", methodName);
1274:
1275:                if (_fieldWriteTransforms == null)
1276:                    _fieldWriteTransforms = newMap();
1277:
1278:                // TODO: Collisions?
1279:
1280:                _fieldWriteTransforms.put(fieldName, body);
1281:
1282:                _formatter.format("replace write %s: %s();\n\n", fieldName,
1283:                        methodName);
1284:            }
1285:
1286:            private void performFieldTransformations() {
1287:                // If no field transformations have been requested, then we can save ourselves some
1288:                // trouble!
1289:
1290:                if (_fieldReadTransforms != null
1291:                        || _fieldWriteTransforms != null)
1292:                    replaceFieldAccess();
1293:
1294:                if (_removedFieldNames != null) {
1295:                    for (String fieldName : _removedFieldNames) {
1296:                        try {
1297:                            CtField field = _ctClass
1298:                                    .getDeclaredField(fieldName);
1299:                            _ctClass.removeField(field);
1300:                        } catch (NotFoundException ex) {
1301:                            throw new RuntimeException(ex);
1302:                        }
1303:                    }
1304:                }
1305:            }
1306:
1307:            static final int SYNTHETIC = 0x00001000;
1308:
1309:            private void replaceFieldAccess() {
1310:                // Provide empty maps here, to make the code in the inner class a tad
1311:                // easier.
1312:
1313:                if (_fieldReadTransforms == null)
1314:                    _fieldReadTransforms = newMap();
1315:
1316:                if (_fieldWriteTransforms == null)
1317:                    _fieldWriteTransforms = newMap();
1318:
1319:                ExprEditor editor = new ExprEditor() {
1320:                    @Override
1321:                    public void edit(FieldAccess access)
1322:                            throws CannotCompileException {
1323:                        // Ignore any methods to were added as part of the transformation.
1324:                        // If we reference the field there, we really mean the field.
1325:
1326:                        if (_addedMethods.contains(access.where()))
1327:                            return;
1328:
1329:                        Map<String, String> transformMap = access.isReader() ? _fieldReadTransforms
1330:                                : _fieldWriteTransforms;
1331:
1332:                        String body = transformMap.get(access.getFieldName());
1333:                        if (body == null)
1334:                            return;
1335:
1336:                        access.replace(body);
1337:                    }
1338:                };
1339:
1340:                try {
1341:                    _ctClass.instrument(editor);
1342:                } catch (CannotCompileException ex) {
1343:                    throw new RuntimeException(ex);
1344:                }
1345:            }
1346:
1347:            public Class toClass(String type) {
1348:                failIfFrozen();
1349:
1350:                // No reason why this can't be allowed to work after freezing.
1351:
1352:                String finalType = TransformUtils.getWrapperTypeName(type);
1353:
1354:                try {
1355:                    return Class.forName(finalType, true, _loader);
1356:                } catch (ClassNotFoundException ex) {
1357:                    throw new RuntimeException(ex);
1358:                }
1359:            }
1360:
1361:            public String getClassName() {
1362:                return _ctClass.getName();
1363:            }
1364:
1365:            public Log getLog() {
1366:                return _log;
1367:            }
1368:
1369:            public void extendConstructor(String statement) {
1370:                notNull(statement, "statement");
1371:
1372:                failIfFrozen();
1373:
1374:                _constructor.append(statement);
1375:                _constructor.append("\n");
1376:            }
1377:
1378:            public String getMethodIdentifier(MethodSignature signature) {
1379:                notNull(signature, "signature");
1380:
1381:                CtMethod method = findMethod(signature);
1382:
1383:                int lineNumber = method.getMethodInfo2().getLineNumber(0);
1384:                CtClass enclosingClass = method.getDeclaringClass();
1385:                String sourceFile = enclosingClass.getClassFile2()
1386:                        .getSourceFile();
1387:
1388:                return format("%s.%s (at %s:%d)", enclosingClass.getName(),
1389:                        signature.getMediumDescription(), sourceFile,
1390:                        lineNumber);
1391:            }
1392:
1393:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.