    001// Licensed under the Apache License, Version 2.0 (the "License");
    002// you may not use this file except in compliance with the License.
    003// You may obtain a copy of the License at
    004//
    005// http://www.apache.org/licenses/LICENSE-2.0
    006//
    007// Unless required by applicable law or agreed to in writing, software
    008// distributed under the License is distributed on an "AS IS" BASIS,
    009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    010// See the License for the specific language governing permissions and
    011// limitations under the License.
    012
    013package org.apache.tapestry5.plastic;
    014
    015import java.lang.annotation.Annotation;
    016import java.lang.reflect.Method;
    017import java.util.List;
    018import java.util.Set;
    019
    020/**
    021 * The representation of a class while it is being instrumented and transformed. PlasticClass allows
    022 * for an imperative style of development: the PlasticClass is provided to other objects; they can query it
    023 * for relevant fields or methods, and invoke methods that modify the class in various ways. Ultimately, the
    024 * end result is a {@link ClassInstantiator} used to create instances of the fully instrumented and transformed class.
    025 *
    026 * The terminology is that a class that is being transformed is "plastic", but the end result is a normal concrete class
    027 * (albeit in a different class loader).
    028 *
    029 * Implements {@link AnnotationAccess} to provide access to annotations on the type itself.
    030 *
    031 * This class is expressly <em>not thread safe</em>; only a single thread should be responsible for operating on a
    032 * PlasticClass.
    033 *
    034 * TODO: what about annotation inheritance?
    035 */
    036@SuppressWarnings("rawtypes")
    037public interface PlasticClass extends AnnotationAccess
    038{
    039    /**
    040     * Returns the fully qualified class name of the class being transformed.
    041     */
    042    String getClassName();
    043
    044    /**
    045     * Matches all fields (claimed or not) that have the given annotation. Returns the fields in sorted order.
    046     *
    047     * @return Unmodifiable List of fields.
    048     */
    049    <T extends Annotation> List<PlasticField> getFieldsWithAnnotation(Class<T> annotationType);
    050
    051    /**
    052     * Returns all non-introduced fields, in sorted order by name.
    053     *
    054     * @return Unmodifiable list of fields.
    055     */
    056    List<PlasticField> getAllFields();
    057
    058    /**
    059     * Returns all unclaimed fields, in sorted order by name. This does not include introduced fields.
    060     *
    061     * @return Unmodifiable list of fields.
    062     * @see PlasticField#claim(Object)
    063     */
    064    List<PlasticField> getUnclaimedFields();
    065
    066    /**
    067     * Introduces a new private field into the class.
    068     *
    069     * @param typeName      the Java class name for the field, or (possibly) a primitive type name or an array
    070     * @param suggestedName the suggested name for the field, which may be modified to ensure that the field name
    071     *                      is unique
    072     * @return PlasticField for the introduced field
    073     */
    074    PlasticField introduceField(String typeName, String suggestedName);
    075
    076    /**
    077     * Convenience method that uses a Java class rather than a type name.
    078     */
    079    PlasticField introduceField(Class fieldType, String suggestedName);
    080
    081    /**
    082     * Introduces a new private method into the class, ensuring that the method name is unique.
    083     *
    084     * @param typeName       return type of method
    085     * @param suggestedName  suggested name for the method; the actual method name may be modified to ensure uniqueness
    086     * @param argumentTypes  types of any arguments (may be null)
    087     * @param exceptionTypes type of any checked exceptions (may be null)
    088     * @return new method, with default implementation
    089     */
    090    PlasticMethod introducePrivateMethod(String typeName, String suggestedName, String[] argumentTypes,
    091                                         String[] exceptionTypes);
    092
    093    /**
    094     * Matches methods with the given annotation.
    095     *
    096     * @return Unmodifiable list of methods, in sorted order.
    097     */
    098    <T extends Annotation> List<PlasticMethod> getMethodsWithAnnotation(Class<T> annotationType);
    099
    100    /**
    101     * Returns all methods of the class, in sorted order. This does not include static methods,
    102     * or any {@linkplain #introduceMethod(MethodDescription) introduced methods}.
    103     *
    104     * @return Unmodifiable list of methods.
    105     */
    106    List<PlasticMethod> getMethods();
    107
    108    /**
    109     * Returns an existing method declared in this class, or introduces a new method into this class.
    110     * The method is created with default behavior. If the method overrides a non-private, non-abstract method
    111     * implemented in a <em>transformed</em> super class, the the default behavior is to invoke that method and return
    112     * its value. Otherwise, the default behavior is to ignore parameters and return 0, false, or null. Void methods
    113     * will invoke the super-class implementation (if it exists) and return no value.
    114     *
    115     * It is allowed for the method description to indicate an abstract method; however the abstract flag will be
    116     * removed, and a non-abstract method will be created.
    117     *
    118     * @param description describes the method name, visibility, return value, etc.
    119     * @return a new (or previously created) PlasticMethod for the method
    120     * @throws IllegalArgumentException if the method is abstract or static
    121     */
    122    PlasticMethod introduceMethod(MethodDescription description);
    123
    124    /**
    125     * Returns an existing method declared in this class, or introduces a new method into this class.
    126     * The method is created with default behavior.
    127     *
    128     * It is allowed for the method description to indicate an abstract method; however the abstract flag will be
    129     * removed, and a non-abstract method will be created.
    130     *
    131     * @param description describes the method name, visibility, return value, etc.
    132     * @param callback    used to create the implementation of the method
    133     * @return a new (or previously created) PlasticMethod for the method
    134     * @throws IllegalArgumentException if the method is abstract or static
    135     */
    136    PlasticMethod introduceMethod(MethodDescription description, InstructionBuilderCallback callback);
    137
    138    /**
    139     * A convenience that creates a {@link MethodDescription} from the Method and introduces that. This is often
    140     * invoked when walking the methods of an interface and introducing each of those methods.
    141     *
    142     * Introduced methods are always concrete, not abstract. The abstract flag on the method modifiers will always be
    143     * stripped off, which is handy when {@linkplain #introduceInterface(Class) introducing methods from an interface}.
    144     *
    145     * @param method to introduce
    146     * @return new (or previously created) PlasticMethod
    147     */
    148    PlasticMethod introduceMethod(Method method);
    149
    150    /**
    151     * Introduces each method defined by the interface into the class. Determines which new methods must
    152     * be introduced in order to ensure that all methods of the interface are implemented. The newly introduced methods,
    153     * if any, are returned.
    154     */
    155    Set<PlasticMethod> introduceInterface(Class interfaceType);
    156
    157    /**
    158     * Introduces the interface, and then invokes {@link PlasticMethod#delegateTo(PlasticField)} on each method
    159     * defined by the interface.
    160     *
    161     * @param interfaceType defines the interface to proxy
    162     * @param field         field containing an object to delegate to
    163     * @return this plastic class, for further configuration
    164     */
    165    PlasticClass proxyInterface(Class interfaceType, PlasticField field);
    166
    167    /**
    168     * Conditionally adds an implementation of <code>toString()</code> to the class, but only if it is not already
    169     * present in the class, or in a (transformed) super-class.
    170     *
    171     * @param toStringValue the fixed value to be returned from invoking toString()
    172     * @return this plastic class, for further configuration
    173     */
    174    PlasticClass addToString(String toStringValue);
    175
    176    /**
    177     * Returns true if this class has an implementation of the indicated method, or a super-class provides
    178     * a non-abstract implementation.
    179     */
    180    boolean isMethodImplemented(MethodDescription description);
    181
    182    /**
    183     * Returns true if this class, or a super-class, implements the indicated interface.
    184     *
    185     * @param interfaceType
    186     * @return true if the interface is implemented
    187     */
    188    boolean isInterfaceImplemented(Class interfaceType);
    189
    190    /**
    191     * Returns the name of the super-class of the class being transformed.
    192     */
    193    String getSuperClassName();
    194
    195    /**
    196     * Adds the callback for execution when an instance of the class is instantiated.
    197     *
    198     * @param callback to execute at instance construction time
    199     */
    200    PlasticClass onConstruct(ConstructorCallback callback);
    201}