// Copyright 2006, 2007, 2008 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package org.apache.tapestry5.services; import javassist.CtBehavior; import org.apache.tapestry5.ioc.AnnotationProvider; import org.slf4j.Logger; import java.lang.annotation.Annotation; import java.util.List; /** * Contains class-specific information used when transforming a raw component class into an executable component class. * An executable class is one that has been transformed to work within Tapestry. This includes adding interfaces * ({@link org.apache.tapestry5.runtime.Component}) but also transforming access to fields, based on annotations and * naming conventions. Most of the changes are provided by different implementations of {@link * ComponentClassTransformWorker}. *
* Much of this information is somewhat like ordinary reflection, but applies to a class that has not yet been loaded. * * Transformation is primarily about identifying annotations on fields and on methods and changing the class, adding new * interfaces, fields and methods, and deleting some existing fields. * * A ClassTransformation contains all the state data specific to a particular class being transformed. A number of * workers will operate upon the ClassTransformation to effect the desired changes before the true class is * loaded into memory. * * Instances of this class are not designed to be thread safe, access to an instance should be restricted to a single * thread. In fact, the design of this type is to allow stateless singletons in multiple threads to work on * thread-specific data (within the ClassTransformation). * * The majority of methods concern the declared members (field and methods) of a specific class, rather than * any fields or methods inherited from a base class. * * @see org.apache.tapestry5.services.TapestryModule#contributeComponentClassTransformWorker(org.apache.tapestry5.ioc.OrderedConfiguration, * org.apache.tapestry5.ioc.ObjectLocator, InjectionProvider, ComponentClassResolver) */ public interface ClassTransformation extends AnnotationProvider { /** * Returns the fully qualified class name of the class being transformed. */ String getClassName(); /** * Returns the name of a new member (field or method). Ensures that the resulting name does not conflict with any * existing member (declared by the underlying class, or inherited from a base class). * * @param suggested the suggested value for the member * @return a unique name for the member */ String newMemberName(String suggested); /** * As with {@link #newMemberName(String)}, but the suggested name is constructed from the prefix and base name. An * underscore will seperate the prefix from the base name. * * @param prefix for the generated name * @param baseName an name, often of an existing field or method * @return a unique name */ String newMemberName(String prefix, String baseName); /** * Generates a list of the names of declared instance fields that have the indicated annotation. Non-private and * static fields are ignored. Only the names of private instance fields are returned. */ List$_ pseudo variable.
*
* The method may be declared in the class, or may be inherited from a super-class. For inherited methods, a method
* is added that first invokes the super implementation. Use {@link #addMethod(TransformMethodSignature, String)}
* when it is necessary to control when the super-class method is invoked.
*
* The extended method is considered new. New methods are not scanned for {@linkplain
* #removeField(String)} removed}, {@linkplain #replaceReadAccess(String, String)} read replaced}, or {@linkplain
* #replaceWriteAccess(String, String) write replaced} fields. Generally that's what you want!
*
* @param methodSignature the signature of the method to extend
* @param methodBody the body of code
* @throws org.apache.tapestry5.internal.services.MethodCompileException
* if the provided Javassist method body can not be compiled
* @see #extendExistingMethod(TransformMethodSignature, String)
*/
void extendMethod(TransformMethodSignature methodSignature, String methodBody);
/**
* Like {@link #extendMethod(TransformMethodSignature, String)}, but the extension does not mark the method as new,
* and field changes will be processed.
*
* @param methodSignature signature of the method to extend
* @param methodBody the body of code
* @throws org.apache.tapestry5.internal.services.MethodCompileException
* if the provided method body can not be compiled
* @see #prefixMethod(TransformMethodSignature, String)
*/
void extendExistingMethod(TransformMethodSignature methodSignature, String methodBody);
/**
* Inserts code at the beginning of a method body (i.e. {@link CtBehavior#insertBefore(String)}.
*
* The method may be declared in the class, or may be inherited from a super-class. For inherited methods, a method
* is added that first invokes the super implementation. Use {@link #addMethod(TransformMethodSignature, String)}
* when it is necessary to control when the super-class method is invoked.
*
*
* Like {@link #extendExistingMethod(TransformMethodSignature, String)}, this method is generally used to "wrap" an
* existing method adding additional functionality such as caching or transaction support.
*
* @param methodSignature
* @param methodBody
* @throws org.apache.tapestry5.internal.services.MethodCompileException
* if the provided method body can not be compiled
*/
void prefixMethod(TransformMethodSignature methodSignature, String methodBody);
/**
* Returns the name of a field that provides the {@link org.apache.tapestry5.ComponentResources} for the transformed
* component. This will be a protected field, accessible to the class and subclasses.
*
* @return name of field
*/
String getResourcesFieldName();
/**
* Adds a new method to the transformed class. Replaces any existing method declared for the class. When overriding
* a super-class method, you should use {@link #extendMethod(TransformMethodSignature, String)}, or you should
* remember to invoke the super class implemetation explicitly. Use this method to control when the super-class
* implementation is invoked.
*/
void addMethod(TransformMethodSignature signature, String methodBody);
/**
* As with {@link #addMethod(TransformMethodSignature, String)}, but field references inside the method
* will be transformed, and the method must not already exist.
*/
void addTransformedMethod(TransformMethodSignature methodSignature, String methodBody);
/**
* Adds a statement to the constructor. The statement is added as is, though a newline is added.
*
* @param statement the statement to add, which should end with a semicolon
*/
void extendConstructor(String statement);
/**
* Replaces all read-references to the specified field with invocations of the specified method name. Replacements
* do not occur in methods added via {@link #addMethod(TransformMethodSignature, String)} or {@link
* #extendMethod(TransformMethodSignature, String)}.
*/
void replaceReadAccess(String fieldName, String methodName);
/**
* Replaces all write accesses to the specified field with invocations of the specified method name. The method
* should take a single parameter of the same type as the field. Replacements do not occur in methods added via
* {@link #addMethod(TransformMethodSignature, String)} or {@link #extendMethod(TransformMethodSignature, String)}.
*/
void replaceWriteAccess(String fieldName, String methodName);
/**
* Removes a field entirely; this is useful for fields that are replaced entirely by computed values.
*
* @param fieldName the name of the field to remove
* @see #replaceReadAccess(String, String)
* @see #replaceWriteAccess(String, String)
*/
void removeField(String fieldName);
/**
* Converts a type name into a corresponding class (possibly, a transformed class). Primitive type names are
* returned as wrapper types.
*/
Class toClass(String type);
/**
* Returns a logger, based on the class name being transformed, to which warnings or errors concerning the class
* being transformed may be logged.
*/
Logger getLogger();
/**
* Returns the modifiers for the named field.
*/
int getFieldModifiers(String fieldName);
/**
* Converts a signature to a string used to identify the method; this consists of the {@link
* TransformMethodSignature#getMediumDescription()} appended with source file information and line number
* information (when available).
*
* @param signature
* @return a string that identifies the class, method name, types of parameters, source file and source line number
*/
String getMethodIdentifier(TransformMethodSignature signature);
/**
* Returns true if this transformation represents a root class (one that extends directly from Object), or false if
* this transformation is an extension of another transformed class.
*
* @return true if root class, false if sub-class
*/
boolean isRootTransformation();
/**
* Adds a catch block to the method. The body should end with a return or a throw. The special Javassist variable
* $e is the exception instance.
*
* @param methodSignature method to be extended.
* @param exceptionType fully qualified class name of exception
* @param body code to execute
*/
void addCatch(TransformMethodSignature methodSignature, String exceptionType, String body);
/**
* Adds method advice for the indicated method.
*/
void advise(TransformMethodSignature methodSignature, ComponentMethodAdvice advice);
/**
* Returns true if the method is an override of a method from the parent class.
*
* @param methodSignature signature of method to check
* @return true if the parent class contains a method with the name signature
*/
boolean isMethodOverride(TransformMethodSignature methodSignature);
}